Package com.aelitis.azureus.core.diskmanager.cache.impl

Source Code of com.aelitis.azureus.core.diskmanager.cache.impl.Test$ChunkSlice

/*
* Created on 04-Aug-2004
* Created by Paul Gardner
* Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/

package com.aelitis.azureus.core.diskmanager.cache.impl;

import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;


import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.torrent.TOTorrentFactory;
import org.gudy.azureus2.core3.torrent.TOTorrentFile;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.core3.logging.*;

import com.aelitis.azureus.core.diskmanager.cache.*;

/**
* @author parg
*
*/


public class
Test
{
  public static void
  main(
    String  []args )
  {
    System.setProperty("azureus.log.stdout","1");
   
    Logger.addListener(new ILogEventListener() {
      public void log(LogEvent event) {
        System.out.println(event.text);
      }
    });
   
    try{
      CacheFileManagerImpl  manager = (CacheFileManagerImpl)CacheFileManagerFactory.getSingleton();
     
      //manager.initialise( false, 8*1024*1024 );
 
      //new Test().writeTest(manager);
     
      manager.initialise( true, true, true, 10*1024*1024, 1024 );

      new Test().pieceReorderTest(manager);
     
    }catch( Throwable e ){
     
      Debug.printStackTrace( e );
    }
  }
 
  public void
  pieceReorderTest(
    CacheFileManagerImpl  manager )
  {
    try{
      Random random = new Random(0);
     
      int  num_files   = 100;
      int  piece_size  = 1024;
      int file_size_average  = piece_size*30;
     
      int  chunk_fixed_size   = 0;
      int chunk_random_size  = 1024;
     
      int  write_order  = 2;    // 0 = linear forwards; 1 = linear backwards; 2 = random;
     
     
     
      int[]  file_sizes = new int[num_files];
     
      for ( int i=0;i<num_files;i++){
       
        file_sizes[i] = random.nextInt( 2*file_size_average ) + 1;
      }
   
      final File  control_dir    = new File("C:\\temp\\filetestcontrol" );
     
      FileUtil.recursiveDelete( control_dir );
     
      control_dir.mkdirs();
 
      File  torrent_file   = new File("C:\\temp\\filetest.torrent" );
     
      torrent_file.delete();
     
      File  source_file_or_dir;
      File  target_file_or_dir;
     
      if ( num_files == 1 ){
       
        source_file_or_dir = new File("C:\\temp\\filetest1.dat" );
        target_file_or_dir = new File("C:\\temp\\filetest2.dat" );
       
        source_file_or_dir.delete();
        target_file_or_dir.delete();
      }else{
       
        source_file_or_dir = new File("C:\\temp\\filetest1.dir" );
        target_file_or_dir = new File("C:\\temp\\filetest2.dir" );
       
        FileUtil.recursiveDelete( source_file_or_dir );
        FileUtil.recursiveDelete( target_file_or_dir );
       
        source_file_or_dir.mkdirs();
        target_file_or_dir.mkdirs();
      }
     
      File[]  source_files = new File[ num_files ];
      File[]  target_files = new File[ num_files ];
     
      RandomAccessFile[]  source_file_rafs = new RandomAccessFile[ num_files ];
     
      final TOTorrent torrent;
     
      for ( int i=0; i<num_files; i++ ){
       
        File  source_file;
        File  target_file;
       
        if  ( num_files == 1 ){
         
          source_file = source_file_or_dir;
          target_file = target_file_or_dir;
         
        }else{
         
          source_file = new File( source_file_or_dir, "file" + i );
          target_file = new File( target_file_or_dir, "file" + i );
        }
       
        source_files[i] = source_file;
        target_files[i= target_file;
       
        FileOutputStream fos = new FileOutputStream( source_file );
       
        byte[]  buffer = new byte[64*1024];
       
        int  rem = file_sizes[i];
       
        while( rem > 0 ){
       
          random.nextBytes( buffer );
       
          int  to_write = rem>buffer.length?buffer.length:rem;
         
          fos.write( buffer, 0, to_write );
         
          rem -= to_write;
        }
       
        fos.close();
       
        source_file_rafs[i] = new RandomAccessFile( source_file, "r" );
      }
     
      torrent =
          TOTorrentFactory.createFromFileOrDirWithFixedPieceLength(
            source_file_or_dir,
            new URL( "http://a.b.c/" ),
            piece_size ).create();
     
      final TOTorrentFile[] torrent_files = torrent.getFiles();
     
        // unfortunately the torrent's file order may not be ours...
     
      for ( int i=0;i<torrent_files.length;i++){

        TOTorrentFile tf = torrent_files[i];
       
        String rel_path = tf.getRelativePath();
       
        boolean  found = false;
       
        for (int j=0;j<source_files.length;j++){
         
          if ( source_files[j].getName().equals( rel_path )){
       
            found = true;
         
            if ( j != i ){
             
              int  temp = file_sizes[i];
              file_sizes[i] = file_sizes[j];
              file_sizes[j] = temp;
             
              File femp = source_files[i];
              source_files[i] = source_files[j];
              source_files[j] = femp;
             
              femp = target_files[i];
              target_files[i] = target_files[j];
              target_files[j] = femp;
             
              RandomAccessFile remp = source_file_rafs[i];
              source_file_rafs[i] = source_file_rafs[j];
              source_file_rafs[j] = remp;
            }
            break;
          }
        }

        if ( !found ){
         
          Debug.out( "eh?" );
         
          return;
        }
      }
     
      CacheFile[] cache_files = new CacheFile[ torrent_files.length ];
     
      for ( int i=0;i<torrent_files.length;i++){
       
        final int f_i = i;
       
        File target_file    = target_files[i];
        final File source_file  = source_files[i];
       
       
        System.out.println( "file " + i + ": e_size=" + file_sizes[i] + ", t_size=" + torrent_files[i].getLength() + ", d_size=" + source_file.length());
       
        cache_files[i] = manager.createFile(
          new CacheFileOwner()
          {
            public String
            getCacheFileOwnerName()
            {
              return( source_file.getAbsolutePath());
            }
           
            public TOTorrentFile
            getCacheFileTorrentFile()
            {
              return( torrent_files[f_i] );
            }
            public File
            getCacheFileControlFileDir()
            {
              return( control_dir );
            }
               public int
            getCacheMode()
            {
              return( CacheFileOwner.CACHE_MODE_NO_CACHE );
            }
          },
          target_file, CacheFile.CT_PIECE_REORDER );
     
        cache_files[i].setAccessMode( CacheFile.CF_WRITE );
      }
     
      List<Chunk> chunks = new ArrayList<Chunk>();
     
      List<Chunk>[] piece_map = new List[ torrent.getNumberOfPieces()];
     
      {
        long  pos       = 0;
        int    file_index    = 0;
        long  file_offset    = 0;
       
        long  total_size   = torrent.getSize();
        long  rem      = total_size;
       
 
        while( rem > 0 ){
         
          long chunk_length;
         
          if ( chunk_fixed_size != 0 ){
           
            chunk_length = chunk_fixed_size;
           
          }else{
           
            chunk_length = random.nextInt( chunk_random_size ) + 1;
          }
         
          if ( rem < chunk_length ){
           
            chunk_length = (int)rem;
          }
                 
          List<ChunkSlice> slices = new ArrayList<ChunkSlice>();
         
          Chunk chunk = new Chunk( pos, chunk_length, slices );
         
          chunks.add( chunk );
           
          while( chunk_length > 0 ){
         
            long  file_size = file_sizes[ file_index ];
 
            long   file_rem = file_size - file_offset;
           
            long  avail = Math.min( file_rem, chunk_length );
           
            if ( avail > 0 ){
     
              int  piece_start  = (int)( pos/piece_size );

              rem -= avail;
              pos  += avail;

              int  piece_end  = (int)((pos-1)/piece_size );
             
              slices.add( new ChunkSlice( file_index, file_offset, avail, piece_start, piece_end ));
            }
           
            chunk_length -= avail;
     
            if ( chunk_length > 0 ){
             
              file_offset  = 0;
             
              file_index++;
             
            }else{
             
              file_offset += avail;
             
              break;
            }
          }
         
          int  piece_start = slices.get(0).getPieceStart();
          int  piece_end   = slices.get(slices.size()-1).getPieceEnd();
         
          for (int i=piece_start;i<=piece_end;i++){
           
            if ( piece_map[i] == null ){
             
              piece_map[i] = new ArrayList<Chunk>();
            }
           
            piece_map[i].add( chunk );
          }
         
          chunk.setPieces( piece_start, piece_end );       

          System.out.println( chunk.getString());   
        }
      }
     
      for (int i=0;i<piece_map.length;i++){
       
        System.out.println( i + ": " + piece_map[i].size());
      }
     
      while ( chunks.size() > 0 ){
       
        Chunk chunk;
       
        if ( write_order == 0 ){
         
          chunk = chunks.remove( 0 );
         
        }else if ( write_order == 1 ){
           
          chunk = chunks.remove( chunks.size() - 1 );
           
        }else{
         
          chunk = chunks.remove( random.nextInt( chunks.size()));
        }
       
        System.out.println( "Processing chunk " + chunk.getString());
       
        List<ChunkSlice> slices = new ArrayList<ChunkSlice>( chunk.getSlices());
       
        if ( write_order == 1 ){
         
          Collections.reverse( slices );
        }
       
        for ( ChunkSlice slice: slices ){
         
          int    file_index   = slice.getFileIndex();
          long  file_offset  = slice.getFileOffset();
          long  length    = slice.getLength();
         

          System.out.println( "Processing slice " + slice.getString() + "[file size=" + file_sizes[file_index]);
         
          DirectByteBuffer  buffer = DirectByteBufferPool.getBuffer( DirectByteBuffer.AL_OTHER, (int)length );
         
          try{
            RandomAccessFile raf = source_file_rafs[ file_index ];
           
            raf.seek( file_offset );
           
            raf.getChannel().read( buffer.getBuffer( DirectByteBuffer.SS_EXTERNAL ));
           
            buffer.flip( DirectByteBuffer.SS_EXTERNAL );
           
            cache_files[file_index].write( buffer, file_offset );
         
          }finally{
           
            buffer.returnToPool();
          }
        }
       
        chunk.setDone();
       
        int  chunk_piece_start   = chunk.getPieceStart();
        int  chunk_piece_end    = chunk.getPieceEnd();
       
        for ( int i=chunk_piece_start;i<=chunk_piece_end;i++){
         
          List<Chunk> pieces = piece_map[i];
         
          boolean complete = true;
         
          for ( Chunk c: pieces ){
           
            if ( !c.isDone()){
             
              complete = false;
             
              break;
            }
          }
         
          if ( complete ){
           
            for ( ChunkSlice slice: slices ){

              if ( i >= slice.getPieceStart() && i <= slice.getPieceEnd()){

                long  piece_offset = i*piece_size;
                int    piece_length;

                if ( i < piece_map.length - 1 ){
                 
                  piece_length = piece_size;
                 
                }else{
                 
                  long  total = torrent.getSize();
                 
                  piece_length = (int)( total - ( total/piece_size )*piece_size );
                 
                  if ( piece_length == 0 ){
                   
                    piece_length = piece_size;
                  }
                }
                           
                DirectByteBuffer  piece_data =
                  DirectByteBufferPool.getBuffer( DirectByteBuffer.AL_OTHER, piece_length );

                long  pos      = 0;
                int    file_index  = 0;
                int    rem      = piece_length;
               
                while( rem > 0 ){
                 
                  long  file_size = file_sizes[ file_index ];
                 
                  long  file_end = pos + file_size;
                 
                  long  avail = file_end - piece_offset;

                  if ( avail > 0 ){
                   
                    int  to_use = (int)Math.min( avail, rem );
                   
                    long file_offset = piece_offset - pos;
                   
                    int  lim = piece_data.limit( DirectByteBuffer.AL_OTHER );
                   
                    piece_data.limit( DirectByteBuffer.AL_OTHER, piece_data.position( DirectByteBuffer.AL_OTHER ) + to_use );
                   
                    cache_files[ file_index ].read( piece_data, file_offset, CacheFile.CP_NONE );
                   
                    piece_data.limit( DirectByteBuffer.AL_OTHER, lim );

                    piece_offset += to_use;
                   
                    rem -= to_use;
                  }
                 
                  file_index++;
                 
                  pos += file_size;
                }
               
                try{
                  cache_files[ slice.getFileIndex()].setPieceComplete(
                    i,
                    piece_data )
                 
                }finally{
                 
                  piece_data.returnToPool();
                }
              }
            }
          }
        }
      }
     
      for (int i=0;i<num_files;i++){
       
        source_file_rafs[i].close();
       
        cache_files[i].close();
       
        byte[]  buffer1 = new byte[256*1024];
        byte[]  buffer2 = new byte[256*1024];
       
        if ( source_files[i].length() != target_files[i].length()){
         
          System.err.println( "File sizes differ for " + i );
        }
       
        FileInputStream  fis1 = new FileInputStream( source_files[i] );
        FileInputStream  fis2 = new FileInputStream( target_files[i] );
       
        long  len = file_sizes[i];
        long  pos  = 0;
       
        boolean  failed = false;
       
        while( len > 0 ){
         
          int  avail = (int)Math.min( len, buffer1.length );
         
          int r1 = fis1.read( buffer1, 0, avail );
          int r2 = fis2.read( buffer2, 0, avail );
         
          if ( r1 != r2 ){
           
            System.err.println( "read lens different: file=" + i + ",pos=" + pos );
           
            failed = true;
           
            break;
           
          }else{
           
            if ( Arrays.equals( buffer1, buffer2 )){
             
              len -= r1;
              pos += r1;
            }else{
             
              int diff_at = -1;
             
              for (int j=0;j<avail;j++){
               
                if ( buffer1[j] != buffer2[j] ){
                 
                  diff_at = j;
                 
                  break;
                }
              }
             
              System.err.println( "mismatch: file=" + i + ",pos=" + pos + " + " + diff_at );
             
              failed = true;
             
              break;
            }
          }
        }
       
        if ( !failed ){
         
          System.out.println( "file " + i + ": matched " + pos + " of " + file_sizes[i] );
         
        }
      }
     
    }catch( Throwable e ){
     
      e.printStackTrace();
    }
  }
 
  public void
  writeTest(
    CacheFileManagerImpl  manager )
  {
    try{
      final File  f = new File("C:\\temp\\cachetest.dat" );
     
      f.delete();
     
      CacheFile  cf = manager.createFile(
          new CacheFileOwner()
          {
            public String
            getCacheFileOwnerName()
            {
              return( "file " + f.toString() );
            }
           
            public TOTorrentFile
            getCacheFileTorrentFile()
            {
              return( null );
            }
            public File
            getCacheFileControlFileDir()
            {
              return null;
            }
               public int
            getCacheMode()
            {
              return( CacheFileOwner.CACHE_MODE_NORMAL );
            }
          },
          f, CacheFile.CT_LINEAR );
     
      cf.setAccessMode( CacheFile.CF_WRITE );
     
      long  start = System.currentTimeMillis();
     
      int    loop  = 10000;
      int    block  = 1*1024;
     
      for (int i=0;i<loop;i++){
       
        DirectByteBuffer  buffer = DirectByteBufferPool.getBuffer( DirectByteBuffer.AL_OTHER, block);
       
        cf.writeAndHandoverBuffer( buffer, i*block);
      }
     
      cf.close();
     
      long   now = System.currentTimeMillis();
     
      long  total = loop*block;
     
      long  elapsed = now - start;
     
      System.out.println( "time = " + elapsed + ", speed = " + (total/elapsed));
     
    }catch( Throwable e ){
     
      Debug.printStackTrace( e );
    }
  }
 
  public void
  manualTest(
    CacheFileManager  manager )
  {
    try{
      final File  f = new File("C:\\temp\\cachetest.dat" );
     
      f.delete();
     
      CacheFile  cf = manager.createFile(
          new CacheFileOwner()
          {
            public String
            getCacheFileOwnerName()
            {
              return( "file " + f.toString() );
            }
           
            public TOTorrentFile
            getCacheFileTorrentFile()
            {
              return( null );
            }
            public File
            getCacheFileControlFileDir()
            {
              return null;
            }
               public int
            getCacheMode()
            {
              return( CacheFileOwner.CACHE_MODE_NORMAL );
            }
          },
          f, CacheFile.CT_LINEAR );
      DirectByteBuffer  write_buffer1 = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_OTHER,512);
      DirectByteBuffer  write_buffer2 = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_OTHER,512);
      DirectByteBuffer  write_buffer3 = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_OTHER,512);
     
      cf.writeAndHandoverBuffer( write_buffer2, 512 );
       
      cf.flushCache();
     
      cf.writeAndHandoverBuffer( write_buffer3, 1024 );
      cf.writeAndHandoverBuffer( write_buffer1, 0 );
     
      cf.flushCache();
     
      write_buffer1 = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_OTHER,512);
      cf.writeAndHandoverBuffer( write_buffer1, 0 );

      cf.flushCache();
       
      cf.close();
     
    }catch( Throwable e ){
     
      Debug.printStackTrace( e );
    }
  }
 
  public void
  randomTest(
    CacheFileManager  manager )
  {
    try{     
      CacheFile[]  files = new CacheFile[3];
     
      byte[][]  file_data  = new byte[3][];
     
      for (int i=0;i<files.length;i++){
       
        final  int f_i = i;
     
        file_data[i] = new byte[randomInt(200000)];
       
        files[i] = manager.createFile(
          new CacheFileOwner()
          {
            public String
            getCacheFileOwnerName()
            {
              return( "file" + f_i );
            }
           
            public TOTorrentFile
            getCacheFileTorrentFile()
            {
              return( null );
            }
            public File
            getCacheFileControlFileDir()
            {
              return null;
            }
               public int
            getCacheMode()
            {
              return( CacheFileOwner.CACHE_MODE_NORMAL );
            }
          },
          new File( "C:\\temp\\cachetest" + i + ".dat" ), CacheFile.CT_LINEAR);
       
        files[i].setAccessMode( CacheFile.CF_WRITE );
       
        DirectByteBuffer bb = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_OTHER,file_data[i].length);
       
        bb.put( DirectByteBuffer.SS_CACHE, file_data[i]);
       
        bb.position(DirectByteBuffer.SS_CACHE, 0);
       
        files[i].write(bb,0);
      }
     
      int  quanitize_to          = 100;
      int quanitize_to_max_consec_write  = 1;
      int quanitize_to_max_consec_read  = 3;
     
      for (int x=0;x<10000000;x++){
       
        int  file_index = randomInt(files.length);
       
        CacheFile  cf = files[file_index];
       
        byte[]  bytes = file_data[ file_index ];
       
       
        int  p1 = randomInt( bytes.length );
        int p2 = randomInt( bytes.length );
       
        p1 = (p1/quanitize_to)*quanitize_to;
        p2 = (p2/quanitize_to)*quanitize_to;
       
        if ( p1 == p2 ){
         
          continue;
        }
       
        int start   = Math.min(p1,p2);
        int len     = Math.max(p1,p2) - start;
       
        int  function = randomInt(100);
       
        if ( function < 30){
         
          if ( len > quanitize_to*quanitize_to_max_consec_read ){
           
            len = quanitize_to*quanitize_to_max_consec_read;
          }
         
          DirectByteBuffer  buffer = DirectByteBufferPool.getBuffer( DirectByteBuffer.AL_OTHER,len );
         
          System.out.println( "read:" + start + "/" + len );
         
          cf.read( buffer, start, CacheFile.CP_READ_CACHE );
         
          buffer.position(DirectByteBuffer.SS_CACHE, 0);
         
          byte[]  data_read = new byte[len];
         
          buffer.get( DirectByteBuffer.SS_CACHE, data_read );
         
          for (int i=0;i<data_read.length;i++){
           
            if ( data_read[i] != bytes[ i+start ]){
             
              throw( new Exception( "data read mismatch" ));
            }
          }
         
          buffer.returnToPool();
         
        }else if ( function < 80 ){
          if ( len > quanitize_to*quanitize_to_max_consec_write ){
           
            len = quanitize_to*quanitize_to_max_consec_write;
          }
         
          System.out.println( "write:" + start + "/" + len );
         
          DirectByteBuffer  buffer = DirectByteBufferPool.getBuffer( DirectByteBuffer.AL_OTHER,len );
         
          for (int i=0;i<len;i++){
           
            bytes[start+i] = (byte)randomInt(256);
           
            buffer.put( DirectByteBuffer.SS_CACHE, bytes[start+i]);
          }
         
          buffer.position(DirectByteBuffer.SS_CACHE, 0);
         
          cf.writeAndHandoverBuffer( buffer, start );
         
        }else if ( function < 90 ){
         
          cf.flushCache();
         
        }else if ( function < 91 ){
         
          cf.clearCache();
         
          //System.out.println( "closing file" );
         
          //cf.close();
        }
      }
     
    }catch( Throwable e ){
     
      Debug.printStackTrace( e );
    }
  }
 
  static int
  randomInt(
    int  num )
  {
    return( (int)(Math.random()*num ));
  }
 
  protected static class
  Chunk
  {
    private long        offset;
    private long        length;
    private List<ChunkSlice>  slices;
   
    private int          piece_start;
    private int          piece_end;
   
    private boolean        is_done;
   
    protected
    Chunk(
      long        _offset,
      long        _length,
      List<ChunkSlice>  _slices )
    {
      offset  = _offset;
      length  = _length;
      slices  = _slices;
    }
   
    protected List<ChunkSlice>
    getSlices()
    {
      return( slices );
    }
   
    protected void
    setPieces(
      int    _piece_start,
      int    _piece_end )
    {
      piece_start  = _piece_start;
      piece_end  = _piece_end;
    }
   
    protected int
      getPieceStart()
      {
        return( piece_start );
      }
   
    protected int
      getPieceEnd()
      {
      return( piece_end );
      }
   
    protected void
    setDone()
    {
      is_done  = true;
    }
   
    protected boolean
    isDone()
    {
      return( is_done );
    }
   
    protected String
    getString()
    {
      String  str = "";
     
      for ( ChunkSlice s: slices ){
       
        str += (str.length()==0?"":",") + s.getString();
      }
     
      return( "offset=" + offset + ",length=" + length + ",slices={" + str + "}" );
    }
  }
 
  protected static class
  ChunkSlice
  {
    private int    file_index;
    private long  file_offset;
    private long  length;
   
    private int    piece_start;
    private int    piece_end;
   
    protected
    ChunkSlice(
      int    _file_index,
      long  _file_offset,
      long  _length,
      int    _piece_start,
      int    _piece_end )
    {
      file_index  = _file_index;
      file_offset  = _file_offset;
      length    = _length;
     
      piece_start  = _piece_start;
      piece_end  = _piece_end;
    }
   
    protected int
    getFileIndex()
    {
      return( file_index );
    }
   
    protected long
    getFileOffset()
    {
      return( file_offset );
    }
   
    protected long
    getLength()
    {
      return( length );
    }
   
    protected int
    getPieceStart()
    {
      return( piece_start );
    }
   
    protected int
    getPieceEnd()
    {
      return( piece_end );
    }
   
    protected String
    getString()
    {
      return( "fi=" + file_index + ",fo=" + file_offset + ",len=" + length + ",ps=" + piece_start + ",pe=" + piece_end);
    }
  }
}
TOP

Related Classes of com.aelitis.azureus.core.diskmanager.cache.impl.Test$ChunkSlice

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.