Package org.apache.poi.hslf.usermodel

Source Code of org.apache.poi.hslf.usermodel.TestRichTextRun

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.poi.hslf.usermodel;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import junit.framework.TestCase;

import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.model.SlideMaster;
import org.apache.poi.hslf.model.TextBox;
import org.apache.poi.hslf.model.TextRun;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.SlideListWithText;

/**
* Test that the friendly getters and setters on RichTextRun
*  behave as expected.
* (model.TestTextRun tests the other functionality)
* @author Nick Burch (nick at torchbox dot com)
*/
public class TestRichTextRun extends TestCase {
  // SlideShow primed on the test data
  private SlideShow ss;
  private SlideShow ssRichA;
  private SlideShow ssRichB;
  private SlideShow ssRichC;
  private HSLFSlideShow hss;
  private HSLFSlideShow hssRichA;
  private HSLFSlideShow hssRichB;
  private HSLFSlideShow hssRichC;
  private String filenameC;
 
    protected void setUp() throws Exception {
    String dirname = System.getProperty("HSLF.testdata.path");
   
    // Basic (non rich) test file
    String filename = dirname + "/basic_test_ppt_file.ppt";
    hss = new HSLFSlideShow(filename);
    ss = new SlideShow(hss);
   
    // Rich test file A
    filename = dirname + "/Single_Coloured_Page.ppt";
    hssRichA = new HSLFSlideShow(filename);
    ssRichA = new SlideShow(hssRichA);
   
    // Rich test file B
    filename = dirname + "/Single_Coloured_Page_With_Fonts_and_Alignments.ppt";
    hssRichB = new HSLFSlideShow(filename);
    ssRichB = new SlideShow(hssRichB);
   
    // Rich test file C - has paragraph styles that run out before
    //   the character ones do
    filenameC = dirname + "/ParagraphStylesShorterThanCharStyles.ppt";
    hssRichC = new HSLFSlideShow(filenameC);
    ssRichC = new SlideShow(hssRichC);
  }

  /**
   * Test the stuff about getting/setting bold
   *  on a non rich text run
   */
  public void testBoldNonRich() throws Exception {
    Slide slideOne = ss.getSlides()[0];
    TextRun[] textRuns = slideOne.getTextRuns();
    RichTextRun rtr = textRuns[0].getRichTextRuns()[0];
   
    assertNull(rtr._getRawCharacterStyle());
    assertNull(rtr._getRawParagraphStyle());
    assertFalse(rtr.isBold());
   
    // Now set it to not bold
    rtr.setBold(false);
    assertNotNull(rtr._getRawCharacterStyle());
    assertNotNull(rtr._getRawParagraphStyle());
    assertFalse(rtr.isBold());
   
    // And now make it bold
    rtr.setBold(true);
    assertNotNull(rtr._getRawCharacterStyle());
    assertNotNull(rtr._getRawParagraphStyle());
    assertTrue(rtr.isBold());
  }

  /**
   * Test the stuff about getting/setting bold
   *  on a rich text run
   */
  public void testBoldRich() throws Exception {
    Slide slideOneR = ssRichA.getSlides()[0];
    TextRun[] textRunsR = slideOneR.getTextRuns();
    RichTextRun[] rtrs = textRunsR[1].getRichTextRuns();
    assertEquals(3, rtrs.length);
   
    assertTrue(rtrs[0].isBold());
    assertFalse(rtrs[1].isBold());
    assertFalse(rtrs[2].isBold());
   
    rtrs[0].setBold(true);
    rtrs[1].setBold(true);
   
    assertTrue(rtrs[0].isBold());
    assertTrue(rtrs[1].isBold());
   
    rtrs[0].setBold(false);
    rtrs[1].setBold(false);
   
    assertFalse(rtrs[0].isBold());
    assertFalse(rtrs[1].isBold());
  }
 
  /**
   * Tests getting and setting the font size on rich and non
   *  rich text runs
   */
  public void testFontSize() throws Exception {
    SlideMaster master;
        Slide slideOne = ss.getSlides()[0];
    TextRun[] textRuns = slideOne.getTextRuns();
    RichTextRun rtr = textRuns[0].getRichTextRuns()[0];
   
    Slide slideOneR = ssRichB.getSlides()[0];
    TextRun[] textRunsR = slideOneR.getTextRuns();
    RichTextRun rtrRa = textRunsR[0].getRichTextRuns()[0];
    RichTextRun rtrRb = textRunsR[1].getRichTextRuns()[0];
    RichTextRun rtrRc = textRunsR[1].getRichTextRuns()[3];

        String defaultFont = "Arial";

    // Start off with rich one
    // First run has defaults
        assertEquals(44, rtrRa.getFontSize());
    assertEquals(defaultFont, rtrRa.getFontName());

    // Second is size 20, default font
    assertEquals(20, rtrRb.getFontSize());
    assertEquals(defaultFont, rtrRb.getFontName());
    // Third is size 24, alt font
    assertEquals(24, rtrRc.getFontSize());
    assertEquals("Times New Roman", rtrRc.getFontName());
   
    // Change 2nd to different size and font
    assertEquals(2, ssRichB.getFontCollection().getChildRecords().length); // Default + TNR
    rtrRb.setFontSize(18);
    rtrRb.setFontName("Courier");
    assertEquals(3, ssRichB.getFontCollection().getChildRecords().length); // Default + TNR + Courier
    assertEquals(18, rtrRb.getFontSize());
    assertEquals("Courier", rtrRb.getFontName());
   
   
    // Now do non rich one
    assertEquals(44, rtr.getFontSize());
    assertEquals(defaultFont, rtr.getFontName());
    assertEquals(1, ss.getFontCollection().getChildRecords().length); // Default
    assertNull(rtr._getRawCharacterStyle());
    assertNull(rtr._getRawParagraphStyle());
   
    // Change Font size
    rtr.setFontSize(99);
    assertEquals(99, rtr.getFontSize());
    assertEquals(defaultFont, rtr.getFontName());
    assertNotNull(rtr._getRawCharacterStyle());
    assertNotNull(rtr._getRawParagraphStyle());
    assertEquals(1, ss.getFontCollection().getChildRecords().length); // Default
   
    // Change Font size and name
    rtr.setFontSize(25);
    rtr.setFontName("Times New Roman");
    assertEquals(25, rtr.getFontSize());
    assertEquals("Times New Roman", rtr.getFontName());
    assertNotNull(rtr._getRawCharacterStyle());
    assertNotNull(rtr._getRawParagraphStyle());
    assertEquals(2, ss.getFontCollection().getChildRecords().length);
  }
 
  public void testChangeWriteRead() throws Exception {
    HSLFSlideShow[] h = new HSLFSlideShow[] { hss, hssRichA, hssRichB };
    Slide[] s = new Slide[] { ss.getSlides()[0], ssRichA.getSlides()[0], ssRichB.getSlides()[0] };
   
    for(int i=0; i<h.length; i++) {
      // Change
      Slide slideOne = s[i];
      TextRun[] textRuns = slideOne.getTextRuns();
      RichTextRun rtr = textRuns[0].getRichTextRuns()[0];
     
      rtr.setBold(true);
      rtr.setFontSize(18);
      rtr.setFontName("Courier");
     
      // Check it took those
      assertEquals(true, rtr.isBold());
      assertEquals(18, rtr.getFontSize());
      assertEquals("Courier", rtr.getFontName());
     
      // Write out and back in
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      h[i].write(baos);
      ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
     
      HSLFSlideShow readHSLF = new HSLFSlideShow(bais);
      SlideShow readS = new SlideShow(readHSLF);
     
      // Tweak existing one again, to ensure really worked
      rtr.setBold(false);
      rtr.setFontSize(17);
      rtr.setFontName("CourierZZ");
     
      // Check it took those changes
      assertEquals(false, rtr.isBold());
      assertEquals(17, rtr.getFontSize());
      assertEquals("CourierZZ", rtr.getFontName());

     
      // Now, look at the one we changed, wrote out, and read back in
      // Ensure it does contain our original modifications
      Slide slideOneRR = readS.getSlides()[0];
      TextRun[] textRunsRR = slideOneRR.getTextRuns();
      RichTextRun rtrRRa = textRunsRR[0].getRichTextRuns()[0];
     
      assertEquals(true, rtrRRa.isBold());
      assertEquals(18, rtrRRa.getFontSize());
      assertEquals("Courier", rtrRRa.getFontName());
    }
  }
 
  /**
   * Test that we can do the right things when the paragraph styles
   *  run out before the character styles do
   */
  public void testParagraphStylesShorterTheCharStyles() {
    // Check we have the right number of sheets
    Slide[] slides = ssRichC.getSlides();
    assertEquals(14, slides.length);
   
    // Check the number of text runs on interesting sheets
    Slide slideThreeC = ssRichC.getSlides()[2];
    Slide slideSevenC = ssRichC.getSlides()[6];
    assertEquals(3, slideThreeC.getTextRuns().length);
    assertEquals(5, slideSevenC.getTextRuns().length);
   
    // On slide three, we should have:
    // TR:
    //   You are an important supplier of various items that I need
    //   .
    // TR:
    //   Source: Internal focus groups
    // TR:
    //   Illustrative Example
    //   .
   
    TextRun[] s3tr = slideThreeC.getTextRuns();
    RichTextRun[] s3rtr0 = s3tr[0].getRichTextRuns();
    RichTextRun[] s3rtr1 = s3tr[1].getRichTextRuns();
    RichTextRun[] s3rtr2 = s3tr[2].getRichTextRuns();
   
    assertEquals(2, s3rtr0.length);
    assertEquals(1, s3rtr1.length);
    assertEquals(2, s3rtr2.length);
   
    assertEquals("You are an important supplier of various items that I need", s3rtr0[0].getText());
    assertEquals("", s3rtr0[1].getText());
    assertEquals("Source: Internal focus groups", s3rtr1[0].getText());
    assertEquals("Illustrative Example", s3rtr2[0].getText());
    assertEquals("", s3rtr2[1].getText());
   
    assertTrue(s3rtr0[0]._isParagraphStyleShared());
    assertTrue(s3rtr0[1]._isParagraphStyleShared());
    assertFalse(s3rtr1[0]._isParagraphStyleShared());
    assertTrue(s3rtr2[0]._isParagraphStyleShared());
    assertTrue(s3rtr2[1]._isParagraphStyleShared());
   
    assertFalse(s3rtr0[0]._isCharacterStyleShared());
    assertFalse(s3rtr0[1]._isCharacterStyleShared());
    assertFalse(s3rtr1[0]._isCharacterStyleShared());
    assertFalse(s3rtr2[0]._isCharacterStyleShared());
    assertFalse(s3rtr2[1]._isCharacterStyleShared());
   
    // On slide seven, we have:
    // TR:
    //  (text)
    // TR:
    //  <ps>(text a)</ps><ps>(text a)(text b)</ps>
    // TR:   
    //  (text)
    TextRun[] s7tr = slideSevenC.getTextRuns();
    RichTextRun[] s7rtr0 = s7tr[0].getRichTextRuns();
    RichTextRun[] s7rtr1 = s7tr[1].getRichTextRuns();
    RichTextRun[] s7rtr2 = s7tr[2].getRichTextRuns();
   
    assertEquals(1, s7rtr0.length);
    assertEquals(3, s7rtr1.length);
    assertEquals(1, s7rtr2.length);
   
    assertFalse(s7rtr0[0]._isParagraphStyleShared());
    assertFalse(s7rtr1[0]._isParagraphStyleShared());
    assertTrue(s7rtr1[1]._isParagraphStyleShared());
    assertTrue(s7rtr1[2]._isParagraphStyleShared());
    assertFalse(s7rtr2[0]._isParagraphStyleShared());
   
    assertFalse(s7rtr0[0]._isCharacterStyleShared());
    assertTrue(s7rtr1[0]._isCharacterStyleShared());
    assertTrue(s7rtr1[1]._isCharacterStyleShared());
    assertFalse(s7rtr1[2]._isCharacterStyleShared());
    assertFalse(s7rtr2[0]._isCharacterStyleShared());
  }
 
  /**
   * Test that we can do the right things when the paragraph styles
   *  run out before the character styles do, when we tweak something
   *  and write back out.
   */
  public void testParagraphStylesShorterTheCharStylesWrite() throws Exception {
    assertMatchesSLTWC(ssRichC);
    assertMatchesFileC(ssRichC);
   
    Slide slideSevenC = ssRichC.getSlides()[6];
    TextRun[] s7tr = slideSevenC.getTextRuns();
    RichTextRun[] s7rtr0 = s7tr[0].getRichTextRuns();
    RichTextRun[] s7rtr1 = s7tr[1].getRichTextRuns();
    RichTextRun[] s7rtr2 = s7tr[2].getRichTextRuns();
   
    String oldText;
   
    // Reset the text on the last run
    // Need to ensure it's a run that really has styles!
    oldText = s7rtr2[0].getRawText();
    s7rtr2[0].setText( oldText );
    assertEquals(oldText, s7rtr2[0].getText());
    assertEquals(oldText, s7tr[2].getText());
    assertEquals(oldText.length() + 1, s7rtr2[0]._getRawCharacterStyle().getCharactersCovered());
    assertEquals(oldText.length() + 1, s7rtr2[0]._getRawParagraphStyle().getCharactersCovered());
    assertMatchesSLTWC(ssRichC);
    assertMatchesFileC(ssRichC);
   
    // Reset the text on a shared paragraph
    oldText = s7rtr1[2].getRawText();
    s7rtr1[2].setText( oldText );
    assertEquals(oldText, s7rtr1[2].getText());
    assertEquals(oldText.length() + 1, s7rtr1[2]._getRawCharacterStyle().getCharactersCovered());
    assertMatchesSLTWC(ssRichC);
    assertMatchesFileC(ssRichC);
   
    // Reset the text on a shared paragraph+character
    s7rtr1[1].setText( s7rtr1[1].getRawText() );
    assertMatchesSLTWC(ssRichC);
    assertMatchesFileC(ssRichC);
  }
 
  /**
   * Opens a new copy of SlideShow C, writes the active
   *  SlideListWithText out, and compares it to the write
   *  out of the supplied SlideShow. Also compares the
   *  contents.
   * @param s
   */
  private void assertMatchesSLTWC(SlideShow s) throws Exception {
    // Grab a new copy of slideshow C
    SlideShow refC = new SlideShow(new HSLFSlideShow(filenameC));

    // Write out the 2nd SLWT in the active document
    SlideListWithText refSLWT = refC.getDocumentRecord().getSlideListWithTexts()[1];
    byte[] raw_slwt = writeRecord(refSLWT);
   
    // Write out the same for the supplied slideshow
    SlideListWithText s_SLWT = s.getDocumentRecord().getSlideListWithTexts()[1];
    byte[] s_slwt = writeRecord(s_SLWT);
   
    // Check the records are the same
    assertEquals(refSLWT.getChildRecords().length, s_SLWT.getChildRecords().length);
    for(int i=0; i<refSLWT.getChildRecords().length; i++) {
      Record ref_r = refSLWT.getChildRecords()[i];
      Record s_r = s_SLWT.getChildRecords()[i];
     
      byte[] r_rb = writeRecord(ref_r);
      byte[] s_rb = writeRecord(s_r);
      assertEquals(r_rb.length, s_rb.length);
      for(int j=0; j<r_rb.length; j++) {
        assertEquals(r_rb[j],s_rb[j]);
      }
    }
   
    // Check the bytes are the same
    assertEquals(raw_slwt.length, s_slwt.length);
    for(int i=0; i<raw_slwt.length; i++) {
      assertEquals(raw_slwt[i], s_slwt[i]);
    }
  }
 
  /**
   * Checks that the supplied slideshow still matches the bytes
   *  of slideshow c
   */
  private void assertMatchesFileC(SlideShow s) throws Exception {
    // Disabled, pending fix of bug #39800
    System.err.println("Skipping test, as would be marked as failed due to bug #39800");
if(false) {
    // Grab the bytes of the file
    FileInputStream fin = new FileInputStream(filenameC);
    ByteArrayOutputStream fb = new ByteArrayOutputStream();
    byte[] b = new byte[4096];
    int read = 0;
    while(read != -1) {
      read = fin.read(b);
      if(read > 0) {
        fb.write(b, 0, read);
      }
    }
    byte[] raw_file = fb.toByteArray();
   
    // Now write out the slideshow
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    s.write(baos);
    byte[] raw_ss = baos.toByteArray();
   
    // Ensure they're the same
    assertEquals(raw_file.length, raw_ss.length);
    for(int i=0; i<raw_file.length; i++) {
      assertEquals(raw_file[i], raw_ss[i]);
    }
}
  }
 
  private byte[] writeRecord(Record r) throws Exception {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    r.writeOut(baos);
    return baos.toByteArray();
  }

    public void testIndentationLevel() throws Exception {
        SlideShow ppt = new SlideShow(new HSLFSlideShow(new File(System.getProperty("HSLF.testdata.path"), "ParagraphStylesShorterThanCharStyles.ppt").getPath()));
        Slide[] sl = ppt.getSlides();
        for (int i = 0; i < sl.length; i++) {
            TextRun[] txt = sl[i].getTextRuns();
            for (int j = 0; j < txt.length; j++) {
                RichTextRun[] rt = txt[j].getRichTextRuns();
                for (int k = 0; k < rt.length; k++) {
                    int indent = rt[k].getIndentLevel();
                    assertTrue(indent >= 0 && indent <= 4 );
                }

            }
        }
    }

    public void testReadParagraphStyles() throws Exception {
        FileInputStream is = new FileInputStream(new File(System.getProperty("HSLF.testdata.path"), "bullets.ppt"));
        SlideShow ppt = new SlideShow(is);
        is.close();
        assertTrue("No Exceptions while reading file", true);

        RichTextRun rt;
        TextRun[] txt;
        Slide[] slide = ppt.getSlides();
        assertEquals(2, slide.length);

        txt = slide[0].getTextRuns();
        assertEquals(2, txt.length);

        assertEquals("Title text", txt[0].getRawText());
        assertEquals(1, txt[0].getRichTextRuns().length);
        rt = txt[0].getRichTextRuns()[0];
        assertFalse(rt.isBullet());

        assertEquals(
                "This is a text placeholder that \r" +
                "follows the design pattern\r" +
                "Defined in the slide master\r" +
                "and has bullets by default", txt[1].getRawText());
        assertEquals(1, txt[1].getRichTextRuns().length);
        rt = txt[1].getRichTextRuns()[0];
        assertEquals('\u2022', rt.getBulletChar());
        assertTrue(rt.isBullet());


        txt = slide[1].getTextRuns();
        assertEquals(2, txt.length);

        assertEquals(
                "I\u2019m a text box\r" +
                "With bullets\r" +
                "That follow the design pattern\r" +
                "From the slide master", txt[0].getRawText());
        assertEquals(1, txt[0].getRichTextRuns().length);
        rt = txt[0].getRichTextRuns()[0];
        assertTrue(rt.isBullet());
        assertEquals('\u2022', rt.getBulletChar());

        assertEquals(
                "I\u2019m a text box with user-defined\r" +
                "bullet character", txt[1].getRawText());
        assertEquals(1, txt[1].getRichTextRuns().length);
        rt = txt[1].getRichTextRuns()[0];
        assertTrue(rt.isBullet());
        assertEquals('\u263A', rt.getBulletChar());
    }

    public void testSetParagraphStyles() throws Exception {
        SlideShow ppt = new SlideShow();

        Slide slide = ppt.createSlide();

        TextBox shape = new TextBox();
        RichTextRun rt = shape.getTextRun().getRichTextRuns()[0];
        shape.setText(
                "Hello, World!\r" +
                "This should be\r" +
                "Multiline text");
        rt.setFontSize(42);
        rt.setBullet(true);
        rt.setTextOffset(50);
        rt.setBulletOffset(0);
        rt.setBulletChar('\u263A');
        slide.addShape(shape);

        assertEquals(42, rt.getFontSize());
        assertEquals(true, rt.isBullet());
        assertEquals(50, rt.getTextOffset());
        assertEquals(0, rt.getBulletOffset());
        assertEquals('\u263A', rt.getBulletChar());

        shape.setAnchor(new java.awt.Rectangle(50, 50, 500, 300));
        slide.addShape(shape);

        //serialize and read again
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ppt.write(out);
        out.close();

        ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));
        slide = ppt.getSlides()[0];
        shape = (TextBox)slide.getShapes()[0];
        rt = shape.getTextRun().getRichTextRuns()[0];
        assertEquals(42, rt.getFontSize());
        assertEquals(true, rt.isBullet());
        assertEquals(50, rt.getTextOffset());
        assertEquals(0, rt.getBulletOffset());
        assertEquals('\u263A', rt.getBulletChar());
    }
   
    public void testAddText() throws Exception {
        FileInputStream is = new FileInputStream(new File(System.getProperty("HSLF.testdata.path"), "bullets.ppt"));
        SlideShow ppt = new SlideShow(is);
        is.close();
        assertTrue("No Exceptions while reading file", true);

        RichTextRun rt;
        TextRun[] txt;
        Slide[] slides = ppt.getSlides();
       
        assertEquals(2, slides.length);
        txt = slides[0].getTextRuns();
        assertEquals(2, txt.length);

        assertEquals("Title text", txt[0].getRawText());
        assertEquals(1, txt[0].getRichTextRuns().length);
        rt = txt[0].getRichTextRuns()[0];
        assertFalse(rt.isBullet());
       
        // Add some new text
        txt[0].appendText("Foo! I'm new!");
        assertEquals(2, txt[0].getRichTextRuns().length);
       
        rt = txt[0].getRichTextRuns()[0];
        assertFalse(rt.isBold());
        assertEquals("Title text", rt.getText());
        rt = txt[0].getRichTextRuns()[1];
        assertFalse(rt.isBold());
        assertEquals("Foo! I'm new!", rt.getText());
        rt.setBold(true);
       
        // And some more
        txt[0].appendText("Me too!");
        assertEquals(3, txt[0].getRichTextRuns().length);
        rt = txt[0].getRichTextRuns()[0];
        assertFalse(rt.isBold());
        assertEquals("Title text", rt.getText());
        rt = txt[0].getRichTextRuns()[1];
        assertTrue(rt.isBold());
        assertEquals("Foo! I'm new!", rt.getText());
        rt = txt[0].getRichTextRuns()[2];
        assertFalse(rt.isBold());
        assertEquals("Me too!", rt.getText());
       
        // Save and re-open
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ppt.write(out);
        out.close();

        ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray()));
        slides = ppt.getSlides();
       
        assertEquals(2, slides.length);
       
        txt = slides[0].getTextRuns();
        assertEquals(2, txt.length);
        assertEquals(3, txt[0].getRichTextRuns().length);
        rt = txt[0].getRichTextRuns()[0];
        assertFalse(rt.isBold());
        assertEquals("Title text", rt.getText());
        rt = txt[0].getRichTextRuns()[1];
        assertTrue(rt.isBold());
        assertEquals("Foo! I'm new!", rt.getText());
        rt = txt[0].getRichTextRuns()[2];
        assertFalse(rt.isBold());
        assertEquals("Me too!", rt.getText());
       
//        FileOutputStream fout = new FileOutputStream("/tmp/foo.ppt");
//        ppt.write(fout);
    }
}
TOP

Related Classes of org.apache.poi.hslf.usermodel.TestRichTextRun

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.