Tuesday, 16 April 2019

split number into it's digits

package sam.numbers;

import java.util.Arrays;

public class SplitNumber {

    public static int[] split(int num) {
        if(num <  10 && num > -10)
            return new int[]{num};
        
        boolean negative = num < 0;
        num = Math.abs(num);
        
        int[] split;
        
        if(num < 100)
            split = new int[2];
        else if(num < 1000)
            split = new int[3];
        else if(num < 10000)
            split = new int[4];
        else 
            split = new int[10];
        
        int k = 0;
        
        while(num > 0) {
            if(k >= split.length)
                Arrays.copyOf(split, split.length + split.length/2 );
            
            split[k++] = num % 10;
            num /= 10;
        }
        
        if(k != split.length)
            split = Arrays.copyOf(split, k);
        
        for (int i = 0, j = split.length - 1; i < j; i++, j--) {
            int t = split[i];
            split[i] = split[j];
            split[j] = t;
        }

        if(negative)
            split[0] = -1 * split[0];
        
        return split;
    }
}


    @Test
    void test() {
        check(1, 1);
        check(-1, -1);
        
        check(-11, -1, 1);
        check(11, 1, 1);
        
        check(-123, -1, 2, 3);
        check(123, 1, 2, 3);
        
        check(-1234, -1, 2, 3, 4);
        check(1234, 1, 2, 3, 4);
        
        check(-1234567, -1, 2, 3, 4,5,6,7);
        check(1234567, 1, 2, 3, 4,5,6,7);
    }

    private void check(int i, int... expected) {
        int[] actual = SplitNumber.split(i);
        
        System.out.printf("%-10s%s\n", i, Arrays.toString(actual));
        assertArrayEquals(expected, actual);
    }


1         [1]
-1        [-1]
-11       [-1, 1]
11        [1, 1]
-123      [-1, 2, 3]
123       [1, 2, 3]
-1234     [-1, 2, 3, 4]
1234      [1, 2, 3, 4]
-1234567  [-1, 2, 3, 4, 5, 6, 7]
1234567   [1, 2, 3, 4, 5, 6, 7]

Split string without using java provided split method

package sam.string;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

public class SplitString {
 public static List<String> split(String s, String delimeter) {
  Objects.requireNonNull(s);
  Objects.requireNonNull(delimeter);
  
  if(s.isEmpty() || delimeter.isEmpty())
   return Collections.singletonList(s);
  
  List<String> list = new ArrayList<>();
  int start = 0, end = 0;
  
  while(true) {
   end = s.indexOf(delimeter, start);
   
   if(end < 0) {
    list.add(s.substring(start));
    break;
   } else {
    list.add(s.substring(start, end));
    start = end + delimeter.length();
   }
  }
  
  return list;
 }

}

test

    @Test
    void test() {
        check("1 2 3", " ");
        check("1122123", "12");
        check("1abc2llc3kollma0allmi", "ll");
        check("ll1abc2llc3kollma0allmi", "ll");
    }

    private void check(String s, String deli) {
        List<String> actual = SplitString.split(s, deli);
        List<String> expected = Pattern.compile(deli, Pattern.LITERAL).splitAsStream(s).collect(Collectors.toList());

        System.out.printf("split(\"%s\", \"%s\") = %s\n", s, deli, actual);
        
        assertEquals(expected, actual);
    }


split("1 2 3", " ") = [1, 2, 3]
split("1122123", "12") = [1, 2, 3]
split("1abc2llc3kollma0allmi", "ll") = [1abc2, c3ko, ma0a, mi]
split("ll1abc2llc3kollma0allmi", "ll") = [, 1abc2, c3ko, ma0a, mi]


code highlighted using: hilite.me

A Product Array Puzzle

Given an array of integers, return a new array such that each element at index i of the new array is the product of all the numbers in the original array except the one at i.

For example, if our input was [1, 2, 3, 4, 5], the expected output would be [120, 60, 40, 30, 24]. If our input was [3, 2, 1], the expected output would be [2, 3, 6].

source: Daily Coding Problem: Problem #2


package sam.numbers;

import java.util.Arrays;

public class ProductArrayPuzzle {
    public static int[] compute(int... array) {
        if(array.length < 2)
            return array;
        
        int multiply = 1;
        for (int i : array) 
            multiply *= i;
        
        for (int i = 0; i < array.length; i++) 
            array[i] = multiply/array[i];
        
        return array;
    }
    
    
    public static int[] computeWithoutDivision(int... array) {
        if(array.length < 2)
            return array;
        
        int[] copy = Arrays.copyOf(array, array.length);
        
        for (int i = 0; i < array.length; i++) {
            int m = 1;
            for (int j = 0; j < copy.length; j++) 
                m *= j == i ? 1 : copy[j];
            
            array[i] = m;
        } 
        
        return array;
    }

}


package sam.numbers;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;

import org.junit.jupiter.api.Test;

public class MainTest {
    @Test
    public void ProductArrayPuzzleTest() {
        assertArrayEquals(ProductArrayPuzzle.compute(1, 2, 3, 4, 5), new int[]{120, 60, 40, 30, 24});
        assertArrayEquals(ProductArrayPuzzle.compute(3, 2, 1), new int[]{2, 3, 6});
        
        assertArrayEquals(ProductArrayPuzzle.computeWithoutDivision(1, 2, 3, 4, 5), new int[]{120, 60, 40, 30, 24});
        assertArrayEquals(ProductArrayPuzzle.computeWithoutDivision(3, 2, 1), new int[]{2, 3, 6});
    }
}


code highlighted using: hilite.me

Wednesday, 14 February 2018

How i'm using JCommander

recently i started using CLI parsers  for my programs. after using some of them, i liked JCommander and this is how i'm using it in my one of programs.




package samrock.app.main;
import static sam.console.ansi.ANSI.yellow;

import java.io.IOException;
import java.util.Comparator;
import java.util.Formatter;
import java.util.List;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;

public class App {
    static final double VERSION = 2.00;

    @Parameter(names= {"-h", "--help"},description = "print this", help=true, order=0)
    public boolean help;

    @Parameter(names= {"-v", "--version"},description = "print version", order=1)
    public boolean version;

    @Parameter(names= {"-c", "--convert"}, description =  "samrock converter", order=2)
    public boolean convert;

    @Parameter(names= {"-s", "--split"}, description =  "Double page splitter", order=3)
    public boolean split;

    @Parameter(names= {"-u","--utils" },description = "Utils", order=4)
    public boolean utils;

    @Parameter
    List<String> argsList;

    //TODO move to samrock tools
    /*
     * @Parameter(names= {"-cmi", "--changeMangaId"},description = "this will make required changes, in databases and files required transition in old manga_id to new manga_id")
    public boolean changeMangaId;
     */



    //TODO move to samrock tools
    // -add      --add-new-manga                      add new manga manually

    public static void main(String[] args) throws IOException {
        if(args.length == 1 && (args[0].equals("-v") || args[0].equals("--version"))) {
            System.out.println(VERSION);
            System.exit(0);
        }
        try {
            new App(args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public App(String[] args) {
        JCommander jc = JCommander.newBuilder()
                .programName("conv")
                .addObject(this).build();
        jc.parse(args);

        if(!(convert || split || utils)) {
            System.out.println(yellow("no options specified"));
            printUsage(jc);
            return;
        }
        SkipOption.init();

        if(convert) {
            Convert c = new Convert();
            jc = check(c, "conv --convert [file]");
        }
        if(split) {
            Split c = new Split();
            jc = check(c, "conv --split [file]");
        }
        if(utils) {
            Utils2 c = new Utils2();
            jc = check(c, "conv --utils ");
        }
    }
    private JCommander check(Object obj, String programName) {
        JCommander jc = JCommander.newBuilder()
                .programName(programName)
                .addObject(obj).build();

        if(help || argsList == null || argsList.isEmpty()) {
            jc.parse("-h");
            printUsage(jc);
        } else {
            jc.parse(argsList.toArray(new String[argsList.size()]));
        }
        return jc;
    }
    private void printUsage(JCommander jc) {
        StringBuilder sb = new StringBuilder();
        Formatter fm = new Formatter(sb);

        yellow(sb, "Usage: ");
        yellow(sb, jc.getProgramName());
        yellow(sb, " [options]\n");

        if(jc.getObjects().get(0) instanceof Convert)
            sb.append("  [file] : is a tsv file cotaining chapters data\n");
        if(jc.getObjects().get(0) instanceof Split)
            sb.append("  [file] : is a folder containing images, \n")
              .append("           if --batch is present then it's a folder containing folders of images\n");

        yellow(sb, "  Options:\n");

        String format2 = "    %-"+(jc.getParameters().stream().mapToInt(p -> p.getNames().length()).max().getAsInt()+5)+"s%s\n";
        jc.getParameters()
        .stream()
        .sorted(Comparator.comparing(p -> p.getParameterAnnotation().order()))
        .forEach(p -> {
            String format = p.getParameterAnnotation().order() >= 20 ? "      "+format2 : format2; 
            if(p.getParameterAnnotation().order() == 10)
                yellow(sb, "\n  Convert Options:\n");
            fm.format(format, p.getNames(), p.getDescription());
        });
        if(jc.getObjects().get(0) == this) {
            yellow(sb, "\nhelp usage:\n")
            .append("  conv --help [option]").append('\n');
            sb.append("   e.g.  ").append('\n');
            sb.append("      conv --help -c").append('\n');
        }

        fm.close();
        System.out.println(sb.toString());
    }
}

download code

styled using hilite.me

Sunday, 8 October 2017

java SE - not so Simple HttpServer

This HttpServer can accept a folder or a zipfile to serve as root.
if the root has a index.html, server will send this as root file to browser otherwise Directory listing is send as root;

(some parts are not complete)


Server.java


package sam.server;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.time.Duration;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import org.kamranzafar.jddl.DirectDownloader;
import org.kamranzafar.jddl.DownloadListener;
import org.kamranzafar.jddl.DownloadTask;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

import static sam.server.Tools.*;

public class Server {
    public static void main(String[] args) throws IOException {
        if (args.length < 1) {
            printUsage();
            System.exit(0);
        }
        Server s = new Server("localhost", 8080);
        s.start(Paths.get(args[0]), true);//args.length > 1 ? "--open".equals(args[1]) : false);
    }

    private static void printUsage() {
        String usage = "" + "usage: java Server [zipfile/folder]"
        /**
         * + " [options] \n\n" 
         * +"options:\n" 
         * + "--port       Port to use [8080]" 
         * + "--address    Address to use [localhost]"
         */
        ;

        System.out.println(yellow(usage));
    }

    static final URI ROOT_URI;

    static {
        URI u = null;
        try {
            u = new URI("/");
        } catch (URISyntaxException e) {
        }
        ROOT_URI = u;
    }

    private ServerRoot file;
    private final HttpServer hs;
    private final Map<String, String> fileext_mimeMap;
    private final int port;

    public Path getRoot(int port) {
        return file == null ? null : file.getRoot();
    }

    public Server(String address, int port) throws IOException {
        this.port = port;

        try(InputStream is = ClassLoader.getSystemResourceAsStream("file.ext-mime.tsv");
                InputStreamReader reader = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(reader)) {
            
            fileext_mimeMap = br.lines()
                    .filter(s -> !s.startsWith("#") && s.indexOf('\t') > 0).map(s -> s.split("\t"))
                    .collect(Collectors.toMap(s -> s[2], s -> s[1], (o, n) -> n));
        }

        hs = HttpServer.create(new InetSocketAddress(address, port), 10);
        hs.createContext(ROOT_URI.toString(), new HttpHandler() {
            @Override
            public void handle(HttpExchange exchange) throws IOException {
                URI uri = exchange.getRequestURI();

                if (uri.equals(ROOT_URI))
                    uri = ROOT_URI.resolve("index.html");

                InputStream is = file.getInputStream(uri);

                if (is == null) {
                    uri = exchange.getRequestURI();
                    List<String> dir = file.walkDirectory(uri);
                    if (dir != null) {
                        StringBuilder sb = new StringBuilder(
                                "<!DOCTYPE html>\r\n<html>\r\n\r\n<head>\r\n    <meta charset=\"utf-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\r\n    <title>")
                                        .append(uri)
                                        .append("</title>\r\n    <meta name=\"description\" content=\"\">\r\n    <meta name=\"author\" content=\"\">\r\n</head>\r\n<style>\r\n:root {\r\n    background-color: #0F0F0F;\r\n    color: white;\r\n    margin-left: 10px;\r\n    font-family: \"Consolas\";\r\n    line-height: 1.6;\r\n}\r\n\r\nul {\r\n    margin: 0;\r\n    padding: 0;\r\n    margin-left: 10px;\r\n}\r\n\r\nul * {\r\n    margin: 0;\r\n    padding: 0;\r\n}\r\n\r\nli {\r\n    list-style: none;\r\n}\r\n\r\nli a {\r\n    text-decoration: none;\r\n    color: white;\r\n    border: 1px solid #353535;\r\n    border-width: 0 0 1px 0;\r\n    padding-bottom: 1px;\r\nmargin-bottom: 1px;\r\n    transition: border-color 0.5s;\r\n    -webkit-transition: border-color 0.5s;\r\n}\r\n\r\nli a:hover {\r\n    border-color: white;\r\n}\r\n\r\n</style>\r\n\r\n<body>\r\n    <h1>Directory List</h1>\r\n    <ul>");

                        URI uri2 = uri;
                        dir.forEach(d -> sb.append("<li><a href='")
                                .append(uri2 + (ROOT_URI.equals(uri2) ? "" : "/")
                                        + Paths.get("/" + d).toUri().toString().replaceFirst("^file:\\/+\\w+:\\/", ""))
                                .append("'>").append(d).append("</a></li>\n"));
                        sb.append("   </ul>\r\n</body>\r\n\r\n</html>\r\n");
                        final byte[] bytes = sb.toString().getBytes();
                        exchange.getResponseHeaders().add("Content-Type", "text/html");
                        exchange.sendResponseHeaders(200, bytes.length);
                        OutputStream resposeBody = exchange.getResponseBody();
                        resposeBody.write(bytes);
                        resposeBody.close();
                    } else {
                        System.out.println(uri + red("  ->  null"));
                        exchange.sendResponseHeaders(404, -1);
                    }
                    return;
                }
                String name = file.getName(uri);
                System.out.println(uri + yellow(" -> ") + name);
                OutputStream resposeBody = exchange.getResponseBody();
                exchange.getResponseHeaders().add("Content-Type", getMime(name));

                // replace link which make create CORS error
                if (name.endsWith("js")) {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
                    int b = 0;
                    while ((b = is.read()) > -1)
                        bos.write(b);

                    String str = new String(bos.toByteArray()).replaceAll("([\"'])(https?://)", "$1/download?$2");
                    byte[] bytes = str.getBytes();
                    exchange.sendResponseHeaders(200, bytes.length);
                    resposeBody.write(bytes);
                } else {
                    exchange.sendResponseHeaders(200, file.getSize(uri));
                    pipe(is, resposeBody);
                }
                resposeBody.close();
                is.close();
            }
        });
        // handle CORS replacement
        hs.createContext("/download", new HttpHandler() {
            @Override
            public void handle(HttpExchange exchange) throws IOException {
                URL url = new URL(exchange.getRequestURI().getQuery());
                InputStream is = null;
                long size = 0;
                String name = null;
                final URI uri = ROOT_URI.resolve(new File(url.getPath()).getName());
                is = file.getInputStream(uri);

                if (is != null) {
                    size = file.getSize(uri);
                    name = file.getName(uri);
                    exchange.getResponseHeaders().add("Content-Type", getMime(name));
                    exchange.sendResponseHeaders(200, size);
                    OutputStream resposeBody = exchange.getResponseBody();
                    pipe(is, resposeBody);
                    System.out.println(url + "  " + name);
                    is.close();
                    resposeBody.close();
                } else {
                    try {
                        downloadAction(url, exchange);
                    } catch (InterruptedException e) {
                        System.out.println("download failed: " + url);
                    }
                }
            }
        });
    }

    private String getMime(String fileName) throws IOException {
        final int index = fileName.indexOf('.');
        if (index < 0) {
            String mime = Files.probeContentType(Paths.get(fileName));
            return mime == null ? "text/plain" : mime;
        }
        String mime = fileext_mimeMap.get(fileName.substring(index));
        return mime == null ? "text/plain" : mime;
    }

    private void pipe(InputStream is, OutputStream resposeBody) throws IOException {
        byte[] bytes = new byte[1024];
        int n = 0;
        while ((n = is.read(bytes)) > 0)
            resposeBody.write(bytes, 0, n);
    }

    public void start(Path root, boolean openInBrowser) throws IOException {
        closeRoot();
        if (Files.notExists(root))
            throw new FileNotFoundException(root.toString());

        if (Files.isRegularFile(root))
            file = new ZipRoot(root);
        else
            file = new DirectoryRoot(root);

        hs.start();
        System.out.println(yellow("server running at: localhost:" + port));
        if (openInBrowser)
            Runtime.getRuntime().exec("explorer http://localhost:" + port);
    }

    public void changeRoot(Path path) throws IOException {
        if (Files.notExists(path))
            throw new FileNotFoundException(path.toString());

        closeRoot();

        if (Files.isRegularFile(path))
            file = new ZipRoot(path);
        else
            file = new DirectoryRoot(path);
    }

    public void closeRoot() throws IOException {
        if (file != null) {
            file.close();
            file = null;
        }
    }

    private DirectDownloader downloader;
    private Thread thread;

    protected void downloadAction(URL url, HttpExchange exchange) throws IOException, InterruptedException {

        if (downloader == null) {
            downloader = new DirectDownloader(4);
            thread = new Thread(downloader);
            thread.setDaemon(true);
            thread.start();
            thread.join();
        }
        FileOutputStream fs = new FileOutputStream("temp");
        downloader.download(new DownloadTask(url, fs, new DownloadListener() {
            double total;
            long last = System.currentTimeMillis();
            int lastTotal = 0;
            int speed = 0;
            String format;
            String name;

            @Override
            public void onUpdate(int bytes, int totalDownloaded) {
                long timepassed = System.currentTimeMillis() - last;
                if (timepassed >= 1000) {
                    double downloaded = totalDownloaded - lastTotal;
                    speed = (int) ((downloaded / timepassed) * (1000d / 1024d));
                    lastTotal = totalDownloaded;
                    last = System.currentTimeMillis();

                    resave_cursor();

                    if (total < 0)
                        System.out.printf(format, bytesToString(totalDownloaded), speed);
                    else
                        System.out.printf(format, bytesToString(totalDownloaded), (totalDownloaded * 100d) / total,
                                speed, durationToString(
                                        Duration.ofSeconds((long) (((total - totalDownloaded) / 1024) / speed))));
                }
            }

            @Override
            public void onStart(String fname, int fsize) {
                total = fsize;
                name = fname;
                System.out.println(yellow(url));
                System.out.println(yellow("file-size: ") + (fsize < 0 ? red(" -- ") : bytesToString(fsize)));
                format = "%s" + cyan(" | ") + (fsize < 0 ? red(" -- ") : green(" %.2f%%")) + cyan(" | ") + "%d Kb/sec"
                        + (fsize < 0 ? "" : cyan(" | ") + yellow("time-left: ") + " %s");
                save_cursor();
            }

            @Override
            public void onComplete() {
                resave_cursor();
                try {
                    fs.flush();
                    fs.close();

                    Path name = Paths.get(url.getPath()).getFileName();
                    Path temp = Paths.get("temp");

                    if (file instanceof ZipRoot)
                        repack((ZipRoot) file, name, temp);
                    else {
                        DirectoryRoot dr = (DirectoryRoot) file;
                        Files.copy(temp, dr.root.resolve(name), StandardCopyOption.REPLACE_EXISTING);
                    }

                    exchange.getResponseHeaders().add("Content-Type", getMime(this.name));
                    exchange.sendResponseHeaders(200, (long) total);
                    OutputStream resposeBody = exchange.getResponseBody();

                    Files.copy(temp, resposeBody);
                    resposeBody.close();
                } catch (IOException e) {
                }
            }

            @Override
            public void onCancel() {
                try {
                    fs.close();
                    Files.deleteIfExists(Paths.get("temp"));
                } catch (IOException e) {
                }
            }
        }));
    }

    protected void repack(final ZipRoot file, final Path name, final Path src) throws IOException {
        Path zipfile = file.file;

        if (Files.notExists(zipfile))
            return;

        file.close();

        Path out = Paths.get(System.currentTimeMillis() + ".zip");

        try (ZipFile zip = new ZipFile(zipfile.toFile());
                OutputStream os = Files.newOutputStream(out, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
                ZipOutputStream zos = new ZipOutputStream(os);) {

            Enumeration<? extends ZipEntry> entries = zip.entries();
            while (entries.hasMoreElements()) {
                ZipEntry ze = entries.nextElement();
                zos.putNextEntry(ze);
                pipe(zip.getInputStream(ze), zos);
            }
            zos.putNextEntry(new ZipEntry(name.toString()));
            Files.copy(src, zos);
        }
        Files.move(out, zipfile, StandardCopyOption.REPLACE_EXISTING);
        System.out.println(yellow("repacked: ") + zipfile.getFileName() + yellow("  added: ") + name);
        this.file = new ZipRoot(zipfile);
    }
}


ServerRoot.java


package sam.server;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.Path;
import java.util.List;

public interface ServerRoot extends AutoCloseable, Closeable {
    InputStream getInputStream(URI uri) throws IOException;
    List<String> walkDirectory(URI uri);
    Path getRoot();
    long getSize(URI uri) throws IOException;
    String getName(URI uri);
    default String toPath(URI uri) {
        return uri.getPath().substring(1);
    }
}

download code

styled using hilite.me