text:
package fastdex.build.lib.aapt;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
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.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public final class FileUtil {

    private static final FileCopyProcessor DEFAULT_FILE_COPY_PROCESSOR = new DefaultFileCopyProcessor();

    private FileUtil() {
    }

    /**
     * is file exist,include directory or file
     *
     * @param path directory or file
     * @return boolean
     */
    public static boolean isExist(String path) {
        File file = new File(path);
        return file.exists();
    }

    /**
     * is has file from directory
     *
     * @param directory
     * @param fileSuffix
     * @return boolean
     */
    public static boolean isHasFile(String directory, String fileSuffix) {
        boolean result = false;
        File directoryFile = new File(directory);
        Queue<File> queue = new ConcurrentLinkedQueue<File>();
        queue.add(directoryFile);
        while (!queue.isEmpty()) {
            File file = queue.poll();
            if (file.isDirectory()) {
                File[] fileArray = file.listFiles();
                if (fileArray != null) {
                    queue.addAll(Arrays.asList(fileArray));
                }
            } else if (file.isFile()) {
                if (file.getName().toLowerCase().endsWith(fileSuffix.toLowerCase())) {
                    result = true;
                    break;
                }
            }
        }
        return result;
    }

    /**
     * create directory
     *
     * @param directoryPath
     */
    public static void createDirectory(final String directoryPath) {
        File file = new File(directoryPath);
        if (!file.exists()) {
            file.setReadable(true, false);
            file.setWritable(true, true);
            file.mkdirs();
        }
    }

    /**
     * create file,full filename,signle empty file.
     *
     * @param fullFilename
     * @return boolean
     */
    public static boolean createFile(final String fullFilename) {
        boolean result = false;
        File file = new File(fullFilename);
        createDirectory(file.getParent());
        try {
            file.setReadable(true, false);
            file.setWritable(true, true);
            result = file.createNewFile();
        } catch (Exception e) {
            throw new FileUtilException(e);
        }
        return result;
    }

    /**
     * delete all file
     *
     * @param directory
     */
    public static void deleteAllFile(String directory) {
        List<File> fileList = new ArrayList<File>();
        File directoryFile = new File(directory);
        Queue<File> queue = new ConcurrentLinkedQueue<File>();
        queue.add(directoryFile);
        while (!queue.isEmpty()) {
            File file = queue.poll();
            if (file.isDirectory()) {
                File[] fileArray = file.listFiles();
                if (fileArray != null) {
                    queue.addAll(Arrays.asList(fileArray));
                }
            }
            fileList.add(file);
        }
        for (int i = fileList.size() - 1; i >= 0; i--) {
            fileList.get(i).delete();
        }
    }

    /**
     * copy file,default path to path
     *
     * @param from
     * @param to
     */
    public static void copyFile(final String from, final String to) {
        copyFile(from, to, FileCopyType.PATH_TO_PATH, DEFAULT_FILE_COPY_PROCESSOR);
    }

    /**
     * copy file
     *
     * @param from
     * @param to
     * @param fileCopyType
     */
    public static void copyFile(final String from, final String to, final FileCopyType fileCopyType) {
        copyFile(from, to, fileCopyType, DEFAULT_FILE_COPY_PROCESSOR);
    }

    /**
     * copy file
     *
     * @param from
     * @param to
     * @param fileCopyType
     * @param fileCopyProcessor
     */
    public static void copyFile(final String from, final String to, final FileCopyType fileCopyType, FileCopyProcessor fileCopyProcessor) {
        switch (fileCopyType) {
            case FILE_TO_PATH:
                copyFileToPath(from, to, fileCopyProcessor);
                break;
            case FILE_TO_FILE:
                copyFileToFile(from, to, fileCopyProcessor);
                break;
            case PATH_TO_PATH:
            default:
                copyPathToPath(from, to, fileCopyProcessor);
                break;
        }
    }

    /**
     * copy path to path,copy process include directory copy
     *
     * @param fromPath
     * @param toPath
     * @param fileCopyProcessor
     */
    public static void copyPathToPath(final String fromPath, final String toPath, FileCopyProcessor fileCopyProcessor) {
        File fromDirectoryFile = new File(fromPath);
        File toDirectoryFile = new File(toPath);
        String fromDirectoryPath = fromDirectoryFile.getAbsolutePath();
        String toDirectoryPath = toDirectoryFile.getAbsolutePath();
        if (fromDirectoryPath.equals(toDirectoryPath)) {
            toDirectoryPath = toDirectoryPath + "_copy";
        }
        Queue<File> queue = new ConcurrentLinkedQueue<File>();
        queue.add(fromDirectoryFile);
        while (!queue.isEmpty()) {
            File file = queue.poll();
            String fromFilePath = file.getAbsolutePath();
            String toFilePath = toDirectoryPath + fromFilePath.substring(fromDirectoryPath.length());
            if (file.isDirectory()) {
                boolean result = true;
                if (fileCopyProcessor != null) {
                    result = fileCopyProcessor.copyFileToFileProcess(fromFilePath, toFilePath, false);
                }
                if (result) {
                    File[] fileArray = file.listFiles();
                    if (fileArray != null) {
                        queue.addAll(Arrays.asList(fileArray));
                    }
                }
            } else if (file.isFile()) {
                if (fileCopyProcessor != null) {
                    fileCopyProcessor.copyFileToFileProcess(fromFilePath, toFilePath, true);
                }
            }
        }
    }

    /**
     * @param fromFile
     * @param toPath
     * @param fileCopyProcessor
     */
    private static void copyFileToPath(final String fromFile, final String toPath, final FileCopyProcessor fileCopyProcessor) {
        File from = new File(fromFile);
        File to = new File(toPath);
        if (from.exists() && from.isFile()) {
            createDirectory(toPath);
            String tempFromFile = from.getAbsolutePath();
            String tempToFile = to.getAbsolutePath() + File.separator + from.getName();
            copyFileToFile(tempFromFile, tempToFile, fileCopyProcessor);
        }
    }

    /**
     * unzip
     *
     * @param zipFullFilename
     * @param outputDirectory
     * @return List<String>
     */
    public static List<String> unzip(String zipFullFilename, String outputDirectory) {
        return unzip(zipFullFilename, outputDirectory, null);
    }

    /**
     * unzip
     *
     * @param zipFullFilename
     * @param outputDirectory
     * @param zipEntryNameList,if it is null or empty,will unzip all
     * @return List<String>
     */
    public static List<String> unzip(String zipFullFilename, String outputDirectory, List<String> zipEntryNameList) {
        if (outputDirectory == null) {
            throw new NullPointerException("out put directory can not be null.");
        }
        List<String> storeFileList = null;
        ZipFile zipFile = null;
        try {
            storeFileList = new ArrayList<String>();
            zipFile = new ZipFile(zipFullFilename);
            String outputDirectoryAbsolutePath = new File(outputDirectory).getAbsolutePath();
            Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
            while (enumeration.hasMoreElements()) {
                ZipEntry zipEntry = enumeration.nextElement();
                String zipEntryName = zipEntry.getName();
                boolean contains = false;
                if (zipEntryNameList == null || zipEntryNameList.isEmpty()) {
                    contains = true;
                } else {
                    if (zipEntryNameList.contains(zipEntryName)) {
                        contains = true;
                    }
                }
                if (contains) {
                    InputStream inputStream = zipFile.getInputStream(zipEntry);
                    String outputFullFilename = outputDirectoryAbsolutePath + Constant.Symbol.SLASH_LEFT + zipEntryName;
                    if (zipEntry.isDirectory()) {
                        createDirectory(outputFullFilename);
                    } else {
                        createFile(outputFullFilename);
                        OutputStream outputStream = new FileOutputStream(outputFullFilename);
                        try {
                            byte[] buffer = new byte[Constant.Capacity.BYTES_PER_KB];
                            int length = -1;
                            while ((length = inputStream.read(buffer, 0, buffer.length)) != -1) {
                                outputStream.write(buffer, 0, length);
                                outputStream.flush();
                            }
                        } finally {
                            if (inputStream != null) {
                                inputStream.close();
                            }
                            if (outputStream != null) {
                                outputStream.close();
                            }
                        }
                        storeFileList.add(outputFullFilename);
                    }
                }
            }
        } catch (Exception e) {
            throw new FileUtilException(e);
        } finally {
            try {
                if (zipFile != null) {
                    zipFile.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return storeFileList;
    }

    /**
     * zip
     *
     * @param outputZipFullFilename
     * @param directory
     */
    public static void zip(String outputZipFullFilename, String directory) {
        zip(outputZipFullFilename, directory, StringUtil.BLANK);
    }

    /**
     * zip
     *
     * @param outputZipFullFilename
     * @param directory
     * @param fileSuffix
     */
    public static void zip(String outputZipFullFilename, String directory, String fileSuffix) {
        List<String> classFileList = FileUtil.findMatchFile(directory, fileSuffix);
        if (classFileList != null && !classFileList.isEmpty()) {
            List<ZipEntryPath> zipEntryPathList = new ArrayList<ZipEntryPath>();
            int classOutputFullFilenameLength = new File(directory).getAbsolutePath().length() + 1;
            for (String classFile : classFileList) {
                String zipEntryName = classFile.substring(classOutputFullFilenameLength, classFile.length());
                zipEntryName = zipEntryName.replace(Constant.Symbol.SLASH_RIGHT, Constant.Symbol.SLASH_LEFT);
                zipEntryPathList.add(new ZipEntryPath(classFile, new ZipEntry(zipEntryName), true));
            }
            zip(outputZipFullFilename, zipEntryPathList);
        }
    }

    /**
     * zip
     *
     * @param outputZipFullFilename
     * @param zipEntryPathList
     */
    public static void zip(String outputZipFullFilename, List<ZipEntryPath> zipEntryPathList) {
        zip(outputZipFullFilename, null, zipEntryPathList);
    }

    /**
     * zip
     *
     * @param outputZipFullFilename
     * @param inputZipFullFilename,can null,the entry will not from the input file
     * @param zipEntryPathList
     */
    public static void zip(String outputZipFullFilename, String inputZipFullFilename, List<ZipEntryPath> zipEntryPathList) {
        zip(outputZipFullFilename, inputZipFullFilename, zipEntryPathList, null);
    }

    /**
     * zip
     *
     * @param outputZipFullFilename
     * @param inputZipFullFilename,can null,the entry will not from the input file
     * @param zipProcessor
     */
    public static void zip(String outputZipFullFilename, String inputZipFullFilename, ZipProcessor zipProcessor) {
        zip(outputZipFullFilename, inputZipFullFilename, null, zipProcessor);
    }

    /**
     * zip
     *
     * @param outputZipFullFilename
     * @param inputZipFullFilename,can null,the entry will not from the input file
     * @param zipEntryPathList
     * @param zipProcessor
     */
    public static void zip(String outputZipFullFilename, String inputZipFullFilename, List<ZipEntryPath> zipEntryPathList, ZipProcessor zipProcessor) {
        ZipOutputStream zipOutputStream = null;
        ZipFile zipFile = null;
        Map<String, ZipEntryPath> zipEntryPathMap = new HashMap<String, ZipEntryPath>();
        List<String> needToAddEntryNameList = new CopyOnWriteArrayList<String>();
        if (zipEntryPathList != null) {
            for (ZipEntryPath zipEntryPath : zipEntryPathList) {
                zipEntryPathMap.put(zipEntryPath.zipEntry.getName(), zipEntryPath);
                needToAddEntryNameList.add(zipEntryPath.zipEntry.getName());
            }
        }
        try {
            createFile(outputZipFullFilename);
            zipOutputStream = new ZipOutputStream(new FileOutputStream(outputZipFullFilename));
            if (inputZipFullFilename != null) {
                zipFile = new ZipFile(inputZipFullFilename);
                Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
                while (enumeration.hasMoreElements()) {
                    ZipEntry zipEntry = enumeration.nextElement();
                    String zipEntryName = zipEntry.getName();
                    InputStream inputStream = null;
                    if (zipEntryPathMap.containsKey(zipEntryName)) {
                        ZipEntryPath zipEntryPath = zipEntryPathMap.get(zipEntryName);
                        needToAddEntryNameList.remove(zipEntryName);
                        if (zipEntryPath.replace) {
                            zipEntry = zipEntryPath.zipEntry;
                            inputStream = new FileInputStream(zipEntryPath.fullFilename);
                        }
                    }
                    if (inputStream == null) {
                        inputStream = zipFile.getInputStream(zipEntry);
                        if (zipProcessor != null) {
                            inputStream = zipProcessor.zipEntryProcess(zipEntryName, inputStream);
                        }
                    }
                    ZipEntry newZipEntry = new ZipEntry(zipEntryName);
                    addZipEntry(zipOutputStream, newZipEntry, inputStream);
                }
            }
            for (String zipEntryName : needToAddEntryNameList) {
                ZipEntryPath zipEntryPath = zipEntryPathMap.get(zipEntryName);
                ZipEntry zipEntry = zipEntryPath.zipEntry;
                InputStream inputStream = new FileInputStream(zipEntryPath.fullFilename);
                if (zipProcessor != null) {
                    inputStream = zipProcessor.zipEntryProcess(zipEntry.getName(), inputStream);
                }
                addZipEntry(zipOutputStream, zipEntry, inputStream);
            }
        } catch (Exception e) {
            throw new FileUtilException(e);
        } finally {
            try {
                if (zipOutputStream != null) {
                    zipOutputStream.finish();
                    zipOutputStream.flush();
                    zipOutputStream.close();
                }
                if (zipFile != null) {
                    zipFile.close();
                }
            } catch (Exception e) {
                throw new FileUtilException(e);
            }
        }
    }

    /**
     * merge zip file
     *
     * @param zipOutputFullFilename
     * @param mergeZipFullFilenameList
     */
    public static void mergeZip(String zipOutputFullFilename, List<String> mergeZipFullFilenameList) {
        FileUtil.createFile(zipOutputFullFilename);
        ZipOutputStream zipOutputStream = null;
        try {
            zipOutputStream = new ZipOutputStream(new FileOutputStream(zipOutputFullFilename));
            if (mergeZipFullFilenameList != null) {
                for (String zipFullFilename : mergeZipFullFilenameList) {
                    if (isExist(zipFullFilename)) {
                        ZipFile zipFile = new ZipFile(zipFullFilename);
                        Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
                        while (enumeration.hasMoreElements()) {
                            ZipEntry zipEntry = enumeration.nextElement();
                            InputStream inputStream = zipFile.getInputStream(zipEntry);
                            addZipEntry(zipOutputStream, zipEntry, inputStream);
                        }
                        zipFile.close();
                    }
                }
            }
        } catch (Exception e) {
            throw new FileUtilException(e);
        } finally {
            try {
                if (zipOutputStream != null) {
                    zipOutputStream.close();
                }
            } catch (Exception e) {
                throw new FileUtilException(e);
            }
        }
    }

    /**
     * add zip entry
     *
     * @param zipOutputStream
     * @param zipEntry
     * @param inputStream
     * @throws Exception
     */
    public static void addZipEntry(ZipOutputStream zipOutputStream, ZipEntry zipEntry, InputStream inputStream) throws Exception {
        try {
            zipOutputStream.putNextEntry(zipEntry);
            byte[] buffer = new byte[Constant.Capacity.BYTES_PER_KB];
            int length = -1;
            while ((length = inputStream.read(buffer, 0, buffer.length)) != -1) {
                zipOutputStream.write(buffer, 0, length);
                zipOutputStream.flush();
            }
        } catch (ZipException e) {
            // do nothing
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            zipOutputStream.closeEntry();
        }
    }

    /**
     * read file
     *
     * @param fullFilename
     * @return byte[]
     */
    public static byte[] readFile(String fullFilename) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(fullFilename);
            copyStream(inputStream, byteArrayOutputStream);
        } catch (FileNotFoundException e) {
            throw new FileUtilException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    throw new FileUtilException(e);
                }
            }
            if (byteArrayOutputStream != null) {
                try {
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    throw new FileUtilException(e);
                }
            }
        }
        return byteArrayOutputStream.toByteArray();
    }

    /**
     * write file
     *
     * @param outputFullFilename
     * @param byteArray
     */
    public static void writeFile(String outputFullFilename, byte[] byteArray) {
        InputStream inputStream = new ByteArrayInputStream(byteArray);
        FileUtil.createFile(outputFullFilename);
        OutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(outputFullFilename);
            copyStream(inputStream, outputStream);
        } catch (FileNotFoundException e) {
            throw new FileUtilException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    throw new FileUtilException(e);
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    throw new FileUtilException(e);
                }
            }
        }
    }

    /**
     * copy stream , from input to output,it don't close
     *
     * @param inputStream
     * @param outputStream
     */
    public static void copyStream(InputStream inputStream, OutputStream outputStream) {
        if (inputStream != null && outputStream != null) {
            try {
                int length = -1;
                byte[] buffer = new byte[Constant.Capacity.BYTES_PER_MB];
                while ((length = inputStream.read(buffer, 0, buffer.length)) != -1) {
                    outputStream.write(buffer, 0, length);
                    outputStream.flush();
                }
            } catch (Exception e) {
                throw new FileUtilException(e);
            }
        }
    }

    /**
     * merge file
     *
     * @param outputFullFilename
     * @param fullFilenameList
     */
    public static void mergeFile(String outputFullFilename, List<String> fullFilenameList) {
        if (fullFilenameList != null && outputFullFilename != null) {
            OutputStream outputStream = null;
            try {
                outputStream = new FileOutputStream(outputFullFilename);
                for (String fullFilename : fullFilenameList) {
                    InputStream inputStream = null;
                    try {
                        inputStream = new FileInputStream(fullFilename);
                        copyStream(inputStream, outputStream);
                    } catch (Exception e) {
                        throw new FileUtilException(e);
                    } finally {
                        if (inputStream != null) {
                            try {
                                inputStream.close();
                            } catch (IOException e) {
                                throw new FileUtilException(e);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                throw new FileUtilException(e);
            } finally {
                if (outputStream != null) {
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        throw new FileUtilException(e);
                    }
                }
            }
        }
    }

    /**
     * find match file directory
     *
     * @param sourceDirectory
     * @param fileSuffix
     * @return List<String>
     */
    public static List<String> findMatchFileDirectory(String sourceDirectory, String fileSuffix) {
        return findMatchFileOrMatchFileDirectory(sourceDirectory, fileSuffix, null, false, true);
    }

    /**
     * find match file directory
     *
     * @param sourceDirectory
     * @param fileSuffix
     * @param includeHidden
     * @return List<String>
     */
    public static List<String> findMatchFileDirectory(String sourceDirectory, String fileSuffix, boolean includeHidden) {
        return findMatchFileOrMatchFileDirectory(sourceDirectory, fileSuffix, null, false, includeHidden);
    }

    /**
     * find match file directory and append some string to rear
     *
     * @param sourceDirectory
     * @param fileSuffix
     * @param somethingAppendToRear
     * @return List<String>
     */
    public static List<String> findMatchFileDirectory(String sourceDirectory, String fileSuffix, String somethingAppendToRear) {
        return findMatchFileOrMatchFileDirectory(sourceDirectory, fileSuffix, somethingAppendToRear, false, true);
    }

    /**
     * find match file directory and append some string to rear
     *
     * @param sourceDirectory
     * @param fileSuffix
     * @param somethingAppendToRear
     * @param includeHidden
     * @return List<String>
     */
    public static List<String> findMatchFileDirectory(String sourceDirectory, String fileSuffix, String somethingAppendToRear, boolean includeHidden) {
        return findMatchFileOrMatchFileDirectory(sourceDirectory, fileSuffix, somethingAppendToRear, false, includeHidden);
    }

    /**
     * find match file
     *
     * @param sourceDirectory
     * @param fileSuffix
     * @return List<String>
     */
    public static List<String> findMatchFile(String sourceDirectory, String fileSuffix) {
        return findMatchFileOrMatchFileDirectory(sourceDirectory, fileSuffix, null, true, true);
    }

    /**
     * find match file
     *
     * @param sourceDirectory
     * @param fileSuffix
     * @param includeHidden
     * @return List<String>
     */
    public static List<String> findMatchFile(String sourceDirectory, String fileSuffix, boolean includeHidden) {
        return findMatchFileOrMatchFileDirectory(sourceDirectory, fileSuffix, null, true, includeHidden);
    }

    /**
     * find match file and append some string to rear
     *
     * @param sourceDirectory
     * @param fileSuffix
     * @param somethingAppendToRear
     * @return List<String>
     */
    public static List<String> findMatchFile(String sourceDirectory, String fileSuffix, String somethingAppendToRear) {
        return findMatchFileOrMatchFileDirectory(sourceDirectory, fileSuffix, somethingAppendToRear, true, false);
    }

    /**
     * find match file and append some string to rear
     *
     * @param sourceDirectory
     * @param fileSuffix
     * @param somethingAppendToRear
     * @param includeHidden
     * @return List<String>
     */
    public static List<String> findMatchFile(String sourceDirectory, String fileSuffix, String somethingAppendToRear, boolean includeHidden) {
        return findMatchFileOrMatchFileDirectory(sourceDirectory, fileSuffix, somethingAppendToRear, true, includeHidden);
    }

    /**
     * find match file or match file directory
     *
     * @param sourceDirectory
     * @param fileSuffix
     * @param somethingAppendToRear
     * @param isFindMatchFile
     * @param includeHidden
     * @return List<String>
     */
    private static List<String> findMatchFileOrMatchFileDirectory(String sourceDirectory, String fileSuffix, String somethingAppendToRear, boolean isFindMatchFile, boolean includeHidden) {
        fileSuffix = StringUtil.nullToBlank(fileSuffix);
        somethingAppendToRear = StringUtil.nullToBlank(somethingAppendToRear);
        List<String> list = new ArrayList<String>();
        File sourceDirectoryFile = new File(sourceDirectory);
        Queue<File> queue = new ConcurrentLinkedQueue<File>();
        queue.add(sourceDirectoryFile);
        while (!queue.isEmpty()) {
            File file = queue.poll();
            boolean result = false;
            if (!file.isHidden() || includeHidden) {
                result = true;
            }
            if (result) {
                if (file.isDirectory()) {
                    File[] fileArray = file.listFiles();
                    if (fileArray != null) {
                        queue.addAll(Arrays.asList(fileArray));
                    }
                } else if (file.isFile()) {
                    if (file.getName().toLowerCase().endsWith(fileSuffix.toLowerCase())) {
                        if (isFindMatchFile) {
                            list.add(file.getAbsolutePath() + somethingAppendToRear);
                        } else {
                            String parentPath = file.getParent();
                            parentPath = parentPath + somethingAppendToRear;
                            if (!list.contains(parentPath)) {
                                list.add(parentPath);
                            }
                        }
                    }
                }
            }
        }
        return list;
    }

    /**
     * get zip entry hash map
     *
     * @param zipFile
     * @return Map<String, String>
     */
    private static Map<String, String> getZipEntryHashMap(String zipFullFilename) {
        ZipFile zipFile = null;
        Map<String, String> map = new HashMap<String, String>();
        try {
            zipFile = new ZipFile(zipFullFilename);
            Enumeration<? extends ZipEntry> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry zipEntry = (ZipEntry) entries.nextElement();
                if (!zipEntry.isDirectory()) {
                    String key = zipEntry.getName();
                    String value = zipEntry.getCrc() + Constant.Symbol.DOT + zipEntry.getSize();
                    map.put(key, value);
                }
            }
        } catch (Exception e) {
            throw new FileUtilException(e);
        } finally {
            if (zipFile != null) {
                try {
                    zipFile.close();
                } catch (IOException e) {
                    throw new FileUtilException(e);
                }
            }
        }
        return map;
    }

    /**
     * differ zip
     *
     * @param differentOutputFullFilename
     * @param oldZipFullFilename
     * @param newZipFullFilename
     */
    public static void differZip(String differentOutputFullFilename, String oldZipFullFilename, String newZipFullFilename) {
        Map<String, String> map = getZipEntryHashMap(oldZipFullFilename);
        ZipFile newZipFile = null;
        ZipOutputStream zipOutputStream = null;
        try {
            newZipFile = new ZipFile(newZipFullFilename);
            Enumeration<? extends ZipEntry> entries = newZipFile.entries();
            FileUtil.createFile(differentOutputFullFilename);
            zipOutputStream = new ZipOutputStream(new FileOutputStream(differentOutputFullFilename));
            while (entries.hasMoreElements()) {
                ZipEntry zipEntry = entries.nextElement();
                if (!zipEntry.isDirectory()) {
                    String zipEntryName = zipEntry.getName();
                    String oldZipEntryHash = map.get(zipEntryName);
                    String newZipEntryHash = zipEntry.getCrc() + Constant.Symbol.DOT + zipEntry.getSize();
                    // old zip entry hash not exist is a new zip entry,if exist
                    // is a modified zip entry
                    if (oldZipEntryHash == null || (!newZipEntryHash.equals(oldZipEntryHash))) {
                        System.out.println(String.format("found modified entry, key=%s(%s/%s)", new Object[]{zipEntryName, oldZipEntryHash, newZipEntryHash}));
                        addZipEntry(zipOutputStream, zipEntry, newZipFile.getInputStream(zipEntry));
                    }
                }
            }
        } catch (Exception e) {
            throw new FileUtilException(e);
        } finally {
            if (newZipFile != null) {
                try {
                    newZipFile.close();
                } catch (IOException e) {
                    throw new FileUtilException(e);
                }
            }
            if (zipOutputStream != null) {
                try {
                    zipOutputStream.finish();
                } catch (IOException e) {
                    throw new FileUtilException(e);
                }
            }
        }
    }

    /**
     * generate simple file
     *
     * @param templateFullFilename
     * @param outputFullFilename
     * @param valueMap
     */
    public static void generateSimpleFile(String templateFullFilename, String outputFullFilename, Map<String, String> valueMap) {
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(templateFullFilename);
            generateSimpleFile(inputStream, outputFullFilename, valueMap);
        } catch (Exception e) {
            throw new FileUtilException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    throw new FileUtilException(e);
                }
            }
        }
    }

    /**
     * generate simple file
     *
     * @param templateInputStream
     * @param outputFullFilename
     * @param valueMap
     */
    public static void generateSimpleFile(InputStream templateInputStream, String outputFullFilename, Map<String, String> valueMap) {
        BufferedReader bufferedReader = null;
        OutputStream outputStream = null;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(templateInputStream, Constant.Encoding.UTF8));
            StringBuilder content = new StringBuilder();
            String line = null;
            Set<Entry<String, String>> entrySet = valueMap.entrySet();
            while ((line = bufferedReader.readLine()) != null) {
                for (Entry<String, String> entry : entrySet) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    line = line.replace(key, value);
                }
                content.append(line);
                content.append(StringUtil.CRLF_STRING);
            }
            createFile(outputFullFilename);
            outputStream = new FileOutputStream(outputFullFilename);
            outputStream.write(content.toString().getBytes(Constant.Encoding.UTF8));
            outputStream.flush();
        } catch (Exception e) {
            throw new FileUtilException(e);
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    throw new FileUtilException(e);
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (Exception e) {
                    throw new FileUtilException(e);
                }
            }
        }
    }

    /**
     * find file list with cache
     *
     * @param sourceDirectoryList
     * @param cacheProperties
     * @param fileSuffix            suffix it will search file in source directory list
     * @param somethingAppendToRear
     * @param isFile                if true the return list is source file else is the source directory
     * @return List<String>
     */
    public static List<String> findFileListWithCache(List<String> sourceDirectoryList, Properties cacheProperties, String fileSuffix, String somethingAppendToRear, boolean isFile) {
        return findFileListWithCache(sourceDirectoryList, cacheProperties, fileSuffix, somethingAppendToRear, isFile, null);
    }

    /**
     * find file list with cache
     *
     * @param sourceDirectoryList
     * @param cacheProperties
     * @param fileSuffix
     * @param somethingAppendToRear
     * @param isFile
     * @param cacheProcessor
     * @return List<String>
     */
    public static List<String> findFileListWithCache(List<String> sourceDirectoryList, Properties cacheProperties, String fileSuffix, String somethingAppendToRear, boolean isFile, CacheProcessor cacheProcessor) {
        return findFileListWithCache(sourceDirectoryList, cacheProperties, fileSuffix, somethingAppendToRear, isFile, false, cacheProcessor);
    }

    /**
     * find file list with cache
     *
     * @param sourceDirectoryList
     * @param cacheProperties
     * @param fileSuffix            suffix it will search file in source directory list
     * @param somethingAppendToRear
     * @param isFile                if true the return list is source file else is the source directory
     * @param includeHidden
     * @return List<String>
     */
    public static List<String> findFileListWithCache(List<String> sourceDirectoryList, Properties cacheProperties, String fileSuffix, String somethingAppendToRear, boolean isFile, boolean includeHidden, CacheProcessor cacheProcessor) {
        List<String> sourceList = new ArrayList<String>();
        //no cache
        if (cacheProperties == null) {
            if (sourceDirectoryList != null && !sourceDirectoryList.isEmpty()) {
                for (String sourceDirectory : sourceDirectoryList) {
                    if (isFile) {
                        sourceList.addAll(FileUtil.findMatchFile(sourceDirectory, fileSuffix, includeHidden));
                    } else {
                        sourceList.addAll(FileUtil.findMatchFileDirectory(sourceDirectory, fileSuffix, somethingAppendToRear, includeHidden));
                    }
                }
            }
        } else if (cacheProperties.isEmpty()) {
            List<String> fileList = new ArrayList<String>();
            if (sourceDirectoryList != null && !sourceDirectoryList.isEmpty()) {
                for (String sourceDirectory : sourceDirectoryList) {
                    fileList.addAll(FileUtil.findMatchFile(sourceDirectory, fileSuffix, includeHidden));
                }
            }
            for (String fullFilename : fileList) {
                String cacheKey = fullFilename;
                if (cacheProcessor != null) {
                    cacheKey = cacheProcessor.keyProcess(cacheKey);
                }
                cacheProperties.setProperty(cacheKey, Generator.md5File(fullFilename));
            }
            if (isFile) {
                sourceList.addAll(fileList);
            } else {
                if (sourceDirectoryList != null && !sourceDirectoryList.isEmpty()) {
                    for (String sourceDirectory : sourceDirectoryList) {
                        sourceList.addAll(FileUtil.findMatchFileDirectory(sourceDirectory, fileSuffix, somethingAppendToRear, includeHidden));
                    }
                }
            }
        } else {
            List<String> fileList = new ArrayList<String>();
            if (sourceDirectoryList != null && !sourceDirectoryList.isEmpty()) {
                for (String sourceDirectory : sourceDirectoryList) {
                    fileList.addAll(FileUtil.findMatchFile(sourceDirectory, fileSuffix, includeHidden));
                }
            }
            for (String fullFilename : fileList) {
                String cacheKey = fullFilename;
                if (cacheProcessor != null) {
                    cacheKey = cacheProcessor.keyProcess(cacheKey);
                }
                String sourceFileMd5 = Generator.md5File(fullFilename);
                if (cacheProperties.containsKey(cacheKey)) {
                    String md5 = cacheProperties.getProperty(cacheKey);
                    if (!sourceFileMd5.equals(md5)) {
                        sourceList.add(fullFilename);
                        cacheProperties.setProperty(cacheKey, sourceFileMd5);
                    }
                } else {
                    sourceList.add(fullFilename);
                    cacheProperties.setProperty(cacheKey, sourceFileMd5);
                }
            }
        }
        return sourceList;
    }

    /**
     * deal with file cache
     *
     * @param propertiesFileMappingFullFilename
     * @param noCacheFileFinder
     * @param noCacheFileProcessor
     * @return List<String>
     */
    public static List<String> dealWithFileCache(String propertiesFileMappingFullFilename, NoCacheFileFinder noCacheFileFinder, NoCacheFileProcessor noCacheFileProcessor) {
        Properties propertiesFileMapping = getPropertiesAutoCreate(propertiesFileMappingFullFilename);
        List<String> noCacheFileList = null;
        if (noCacheFileFinder == null) {
            throw new NullPointerException("noCacheFileFinder can not be null.");
        }
        noCacheFileList = noCacheFileFinder.findNoCacheFileList(propertiesFileMapping);
        boolean saveCache = false;
        if (noCacheFileProcessor != null) {
            saveCache = noCacheFileProcessor.process(noCacheFileList);
        }
        if (saveCache) {
            saveProperties(propertiesFileMapping, propertiesFileMappingFullFilename);
        }
        return noCacheFileList;
    }

    /**
     * get properties will auto create
     *
     * @param propertiesFullFilename
     * @return Properties
     */
    public static Properties getPropertiesAutoCreate(String propertiesFullFilename) {
        if (!FileUtil.isExist(propertiesFullFilename)) {
            FileUtil.createFile(propertiesFullFilename);
        }
        return getProperties(propertiesFullFilename);
    }

    /**
     * get properties
     *
     * @param propertiesFullFilename
     * @return Properties
     */
    public static Properties getProperties(String propertiesFullFilename) {
        Properties properties = null;
        if (propertiesFullFilename != null) {
            InputStream inputStream = null;
            try {
                inputStream = new FileInputStream(propertiesFullFilename);
                properties = new Properties();
                properties.load(inputStream);
            } catch (Exception e) {
                throw new FileUtilException(e);
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (Exception e) {
                        throw new FileUtilException(e);
                    }
                }
            }
        }
        return properties;
    }

    /**
     * get properties from properties file,will auto create
     *
     * @param file
     * @return Properties
     * @throws IOException
     */
    public static Properties getProperties(File file) {
        Properties properties = null;
        if (file != null) {
            properties = getProperties(file.getAbsolutePath());
        }
        return properties;
    }

    /**
     * save properties
     *
     * @param properties
     * @param outputFullFilename
     */
    public static void saveProperties(Properties properties, String outputFullFilename) {
        if (properties != null && outputFullFilename != null) {
            OutputStream outputStream = null;
            try {
                outputStream = new FileOutputStream(outputFullFilename);
                properties.store(outputStream, null);
            } catch (Exception e) {
                throw new FileUtilException(e);
            } finally {
                if (outputStream != null) {
                    try {
                        outputStream.flush();
                        outputStream.close();
                    } catch (Exception e) {
                        throw new FileUtilException(e);
                    }
                }
            }
        }
    }

    /**
     * @param fromFile
     * @param toFile
     * @param fileCopyProcessor
     */
    private static void copyFileToFile(final String fromFile, final String toFile, FileCopyProcessor fileCopyProcessor) {
        if (fileCopyProcessor != null) {
            createFile(toFile);
            fileCopyProcessor.copyFileToFileProcess(fromFile, toFile, true);
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        String outputZipFullFilename = "/D:/a/b.zip";
        mergeZip(outputZipFullFilename, Arrays.asList("/D:/a.zip", "/D:/b.zip"));
    }

    public enum FileCopyType {
        PATH_TO_PATH, FILE_TO_PATH, FILE_TO_FILE
    }

    public interface FileCopyProcessor {

        /**
         * copyFileToFileProcess
         *
         * @param from,maybe   directory
         * @param to,maybe     directory
         * @param isFile,maybe directory or file
         * @return boolean, if true keep going copy,only active in directory so
         * far
         */
        boolean copyFileToFileProcess(final String from, final String to, final boolean isFile);

    }

    public interface ZipProcessor {

        /**
         * zip entry process
         *
         * @param zipEntryName
         * @param inputStream
         * @return InputStream
         */
        InputStream zipEntryProcess(final String zipEntryName, InputStream inputStream);
    }

    public interface CacheProcessor {
        /**
         * key process,can change key to save cache
         *
         * @param cacheKey
         * @return String
         */
        String keyProcess(final String key);
    }

    public interface NoCacheFileProcessor {
        /**
         * process
         *
         * @param uncachedFileList
         * @return boolean, true is save cache else false
         */
        boolean process(List<String> uncachedFileList);
    }

    public interface NoCacheFileFinder {

        /**
         * find no cache file list
         *
         * @param cacheFileMapping
         * @return List<String>
         */
        List<String> findNoCacheFileList(Properties cacheFileMapping);
    }

    public static class ZipEntryPath {
        private String   fullFilename = null;
        private ZipEntry zipEntry     = null;
        private boolean  replace      = false;

        public ZipEntryPath(String fullFilename, ZipEntry zipEntry) {
            this(fullFilename, zipEntry, false);
        }

        public ZipEntryPath(String fullFilename, ZipEntry zipEntry, boolean replace) {
            this.fullFilename = fullFilename;
            this.zipEntry = zipEntry;
            this.replace = replace;
        }
    }

    public static class FileUtilException extends RuntimeException {
        private static final long serialVersionUID = 3884649425767533205L;

        public FileUtilException(Throwable cause) {
            super(cause);
        }
    }

}


text:
layout: page
title: Trabalhos Investigativos
---

Trabalhos Investigativos

            Information Technology Management IV - Individual Assignment - August 2015

            News Feed Reader Application - 22 May 2013

redpajama_set_name: RedPajamaGithub


text:
[![Build Status](https://travis-ci.org/MashSoftware/petitions.svg?branch=master)](https://travis-ci.org/MashSoftware/petitions)

## Getting Started

```
export TWFY_API_KEY=<your_they_work_for_you_api_key>
export FLASK_APP=mash_petitions/__init__.py
export FLASK_DEBUG=1
```

## Running
```
flask run
```


text:
require_relative "./helper"

class TestLanguage < Minitest::Test
  include Linguist

  def test_find_by_alias
    assert_equal Language['ASP'], Language.find_by_alias('asp')
    assert_equal Language['ASP'], Language.find_by_alias('aspx')
    assert_equal Language['ASP'], Language.find_by_alias('aspx-vb')
    assert_equal Language['ActionScript'], Language.find_by_alias('as3')
    assert_equal Language['ApacheConf'], Language.find_by_alias('apache')
    assert_equal Language['Assembly'], Language.find_by_alias('nasm')
    assert_equal Language['Batchfile'], Language.find_by_alias('bat')
    assert_equal Language['C#'], Language.find_by_alias('c#')
    assert_equal Language['C#'], Language.find_by_alias('csharp')
    assert_equal Language['C'], Language.find_by_alias('c')
    assert_equal Language['C++'], Language.find_by_alias('c++')
    assert_equal Language['C++'], Language.find_by_alias('cpp')
    assert_equal Language['Chapel'], Language.find_by_alias('chpl')
    assert_equal Language['CoffeeScript'], Language.find_by_alias('coffee')
    assert_equal Language['CoffeeScript'], Language.find_by_alias('coffee-script')
    assert_equal Language['ColdFusion'], Language.find_by_alias('cfm')
    assert_equal Language['Common Lisp'], Language.find_by_alias('common-lisp')
    assert_equal Language['Common Lisp'], Language.find_by_alias('lisp')
    assert_equal Language['Darcs Patch'], Language.find_by_alias('dpatch')
    assert_equal Language['Dart'], Language.find_by_alias('dart')
    assert_equal Language['Emacs Lisp'], Language.find_by_alias('elisp')
    assert_equal Language['Emacs Lisp'], Language.find_by_alias('emacs')
    assert_equal Language['Emacs Lisp'], Language.find_by_alias('emacs-lisp')
    assert_equal Language['Gettext Catalog'], Language.find_by_alias('pot')
    assert_equal Language['HTML'], Language.find_by_alias('html')
    assert_equal Language['HTML'], Language.find_by_alias('xhtml')
    assert_equal Language['HTML+ERB'], Language.find_by_alias('html+erb')
    assert_equal Language['HTML+ERB'], Language.find_by_alias('erb')
    assert_equal Language['IRC log'], Language.find_by_alias('irc')
    assert_equal Language['JSON'], Language.find_by_alias('json')
    assert_equal Language['Java Server Pages'], Language.find_by_alias('jsp')
    assert_equal Language['Java'], Language.find_by_alias('java')
    assert_equal Language['JavaScript'], Language.find_by_alias('javascript')
    assert_equal Language['JavaScript'], Language.find_by_alias('js')
    assert_equal Language['Literate Haskell'], Language.find_by_alias('lhs')
    assert_equal Language['Literate Haskell'], Language.find_by_alias('literate-haskell')
    assert_equal Language['Objective-C'], Language.find_by_alias('objc')
    assert_equal Language['OpenEdge ABL'], Language.find_by_alias('openedge')
    assert_equal Language['OpenEdge ABL'], Language.find_by_alias('progress')
    assert_equal Language['OpenEdge ABL'], Language.find_by_alias('abl')
    assert_equal Language['Parrot Internal Representation'], Language.find_by_alias('pir')
    assert_equal Language['PowerShell'], Language.find_by_alias('posh')
    assert_equal Language['Puppet'], Language.find_by_alias('puppet')
    assert_equal Language['Pure Data'], Language.find_by_alias('pure-data')
    assert_equal Language['Raw token data'], Language.find_by_alias('raw')
    assert_equal Language['Ruby'], Language.find_by_alias('rb')
    assert_equal Language['Ruby'], Language.find_by_alias('ruby')
    assert_equal Language['R'], Language.find_by_alias('r')
    assert_equal Language['Scheme'], Language.find_by_alias('scheme')
    assert_equal Language['Shell'], Language.find_by_alias('bash')
    assert_equal Language['Shell'], Language.find_by_alias('sh')
    assert_equal Language['Shell'], Language.find_by_alias('shell')
    assert_equal Language['Shell'], Language.find_by_alias('zsh')
    assert_equal Language['SuperCollider'], Language.find_by_alias('supercollider')
    assert_equal Language['TeX'], Language.find_by_alias('tex')
    assert_equal Language['TypeScript'], Language.find_by_alias('ts')
    assert_equal Language['Vim script'], Language.find_by_alias('vim')
    assert_equal Language['Vim script'], Language.find_by_alias('viml')
    assert_equal Language['reStructuredText'], Language.find_by_alias('rst')
    assert_equal Language['YAML'], Language.find_by_alias('yml')
    assert_nil Language.find_by_alias(nil)
  end

  # Note these are set by script/set-language-ids. If these tests fail then someone
  # has changed the language_id fields set in languages.yml which is almost certainly
  # not what you want to happen (these fields are used in GitHub's search indexes)
  def test_language_ids
    assert_equal 4, Language['ANTLR'].language_id
    assert_equal 54, Language['Ceylon'].language_id
    assert_equal 326, Language['Ruby'].language_id
    assert_equal 421, Language['xBase'].language_id
  end

  def test_find_by_id
    assert_equal Language['Elixir'], Language.find_by_id(100)
    assert_equal Language['Ruby'], Language.find_by_id(326)
    assert_equal Language['xBase'], Language.find_by_id(421)
  end

  def test_groups
    # Test a couple identity cases
    assert_equal Language['Perl'], Language['Perl'].group
    assert_equal Language['Python'], Language['Python'].group
    assert_equal Language['Ruby'], Language['Ruby'].group

    # Test a few special groups
    assert_equal Language['Assembly'], Language['Unix Assembly'].group
    assert_equal Language['C'], Language['OpenCL'].group
    assert_equal Language['Haskell'], Language['Literate Haskell'].group
    assert_equal Language['Java'], Language['Java Server Pages'].group
    assert_equal Language['Python'], Language['Cython'].group
    assert_equal Language['Python'], Language['NumPy'].group
    assert_equal Language['Shell'], Language['Gentoo Ebuild'].group
    assert_equal Language['Shell'], Language['Gentoo Eclass'].group
    assert_equal Language['Shell'], Language['Tcsh'].group

    # Ensure everyone has a group
    Language.all.each do |language|
      assert language.group, "#{language} has no group"
    end
  end

  def test_popular
    assert Language['Ruby'].popular?
    assert Language['Perl'].popular?
    assert Language['Python'].popular?
    assert Language['Assembly'].unpopular?
    assert Language['Brainfuck'].unpopular?
  end

  def test_programming
    assert_equal :programming, Language['JavaScript'].type
    assert_equal :programming, Language['LSL'].type
    assert_equal :programming, Language['Perl'].type
    assert_equal :programming, Language['PowerShell'].type
    assert_equal :programming, Language['Python'].type
    assert_equal :programming, Language['Ruby'].type
    assert_equal :programming, Language['TypeScript'].type
    assert_equal :programming, Language['Makefile'].type
    assert_equal :programming, Language['SuperCollider'].type
  end

  def test_markup
    assert_equal :markup, Language['HTML'].type
    assert_equal :markup, Language['SCSS'].type
  end

  def test_data
    assert_equal :data, Language['YAML'].type
  end

  def test_prose
    assert_equal :prose, Language['Markdown'].type
    assert_equal :prose, Language['Org'].type
  end

  def test_searchable
    assert Language['Ruby'].searchable?
    assert !Language['Gettext Catalog'].searchable?
    assert Language['SQL'].searchable?
  end

  def test_find_by_name
    assert_nil Language.find_by_name(nil)
    ruby = Language['Ruby']
    assert_equal ruby, Language.find_by_name('Ruby')
  end

  def test_find_all_by_name
    Language.all.each do |language|
      assert_equal language, Language.find_by_name(language.name)
      assert_equal language, Language[language.name]
    end
  end

  def test_find_all_by_alias
    Language.all.each do |language|
      language.aliases.each do |name|
        assert_equal language, Language.find_by_alias(name)
        assert_equal language, Language[name]
      end
    end
  end

  def test_find_by_extension
    assert_equal [], Language.find_by_extension('.factor-rc')
    assert_equal [Language['Limbo'], Language['M'], Language['MUF'], Language['Mathematica'], Language['Matlab'], Language['Mercury'], Language['Objective-C']], Language.find_by_extension('foo.m')
    assert_equal [Language['Ruby']], Language.find_by_extension('foo.rb')
    assert_equal [Language['Ruby']], Language.find_by_extension('foo/bar.rb')
    assert_equal [Language['Ruby']], Language.find_by_extension('PKGBUILD.rb')
    assert_equal ['C', 'C++', 'Objective-C'], Language.find_by_extension('foo.h').map(&:name).sort
    assert_equal [], Language.find_by_extension('rb')
    assert_equal [], Language.find_by_extension('.null')
    assert_equal [Language['HTML+Django']], Language.find_by_extension('index.jinja')
    assert_equal [Language['Chapel']], Language.find_by_extension('examples/hello.chpl')
    assert_equal [], Language.find_by_filename('F.I.L.E.')
  end

  def test_find_all_by_extension
    Language.all.each do |language|
      language.extensions.each do |extension|
        assert_includes Language.find_by_extension(extension), language
      end
    end
  end

  def test_find_by_filename
    assert_equal [Language['Shell']], Language.find_by_filename('PKGBUILD')
    assert_equal [Language['Ruby']], Language.find_by_filename('Rakefile')
    assert_equal Language['ApacheConf'], Language.find_by_filename('httpd.conf').first
    assert_equal [Language['ApacheConf']], Language.find_by_filename('.htaccess')
    assert_equal Language['Nginx'], Language.find_by_filename('nginx.conf').first
    assert_equal [], Language.find_by_filename('foo.rb')
    assert_equal [], Language.find_by_filename('rb')
    assert_equal [], Language.find_by_filename('.null')
    assert_equal [Language['Shell']], Language.find_by_filename('.bashrc')
    assert_equal [Language['Shell']], Language.find_by_filename('bash_profile')
    assert_equal [Language['Shell']], Language.find_by_filename('.zshrc')
    assert_equal [Language['Clojure']], Language.find_by_filename('riemann.config')
  end

  def test_find_by_interpreter
    {
      "ruby" => "Ruby",
      "Rscript" => "R",
      "sh" => "Shell",
      "bash" => "Shell",
      "python" => "Python",
      "python2" => "Python",
      "python3" => "Python",
      "sbcl" => "Common Lisp",
      "sclang" => "SuperCollider"
    }.each do |interpreter, language|
      assert_equal [Language[language]], Language.find_by_interpreter(interpreter)
    end

    assert_equal [], Language.find_by_interpreter(nil)
  end

  def test_find
    assert_equal 'Ruby', Language['Ruby'].name
    assert_equal 'Ruby', Language['ruby'].name
    assert_equal 'C++', Language['C++'].name
    assert_equal 'C++', Language['c++'].name
    assert_equal 'C++', Language['cpp'].name
    assert_equal 'C#', Language['C#'].name
    assert_equal 'C#', Language['c#'].name
    assert_equal 'C#', Language['csharp'].name
    assert_nil Language['defunkt']
    assert_nil Language[nil]
  end

  def test_find_ignores_case
    assert_equal 'AGS Script', Language['ags script'].name
    assert_equal 'AGS Script', Language['ags sCRIPT'].name
  end

  def test_find_by_name_ignores_case
    assert_equal 'AGS Script', Language.find_by_name('ags script').name
    assert_equal 'AGS Script', Language.find_by_name('ags sCRIPT').name
  end

  def test_find_by_alias_ignores_case
    refute_includes Language['AGS Script'].aliases, 'AGS'
    assert_equal 'AGS Script', Language.find_by_alias('AGS').name
  end

  def test_find_ignores_comma
    assert_equal 'Rust', Language['rust,no_run'].name
  end

  def test_find_by_name_ignores_comma
    assert_equal Language['Rust'], Language.find_by_name('rust,no_run')
  end

  def test_find_by_alias_ignores_comma
    assert_equal Language['Rust'], Language.find_by_alias('rust,no_run')
  end

  def test_doesnt_blow_up_with_blank_lookup
    assert_nil Language.find_by_alias('')
    assert_nil Language.find_by_name(nil)
    assert_nil Language[""]
  end

  def test_name
    assert_equal 'Perl',   Language['Perl'].name
    assert_equal 'Python', Language['Python'].name
    assert_equal 'Ruby',   Language['Ruby'].name
  end

  def test_escaped_name
    assert_equal 'C', Language['C'].escaped_name
    assert_equal 'C%23', Language['C#'].escaped_name
    assert_equal 'C%2B%2B', Language['C++'].escaped_name
    assert_equal 'Objective-C', Language['Objective-C'].escaped_name
    assert_equal 'Common%20Lisp', Language['Common Lisp'].escaped_name
  end

  def test_error_without_name
    assert_raises ArgumentError do
      Language.new :name => nil
    end
  end

  def test_color
    assert_equal '#701516', Language['Ruby'].color
    assert_equal '#3572A5', Language['Python'].color
    assert_equal '#f1e05a', Language['JavaScript'].color
    assert_equal '#2b7489', Language['TypeScript'].color
    assert_equal '#3d9970', Language['LSL'].color
  end

  def test_colors
    assert Language.colors.include?(Language['Ruby'])
    assert Language.colors.include?(Language['Python'])
  end

  def test_ace_mode
    assert_equal 'c_cpp', Language['C++'].ace_mode
    assert_equal 'coffee', Language['CoffeeScript'].ace_mode
    assert_equal 'csharp', Language['C#'].ace_mode
    assert_equal 'css', Language['CSS'].ace_mode
    assert_equal 'lsl', Language['LSL'].ace_mode
    assert_equal 'javascript', Language['JavaScript'].ace_mode
    assert_equal 'text', Language['FORTRAN'].ace_mode
  end

  def test_codemirror_mode
    assert_equal 'ruby', Language['Ruby'].codemirror_mode
    assert_equal 'javascript', Language['JavaScript'].codemirror_mode
    assert_equal 'clike', Language['C'].codemirror_mode
    assert_equal 'clike', Language['C++'].codemirror_mode
  end

  def test_codemirror_mime_type
    assert_equal 'text/x-ruby', Language['Ruby'].codemirror_mime_type
    assert_equal 'text/javascript', Language['JavaScript'].codemirror_mime_type
    assert_equal 'text/x-csrc', Language['C'].codemirror_mime_type
    assert_equal 'text/x-c++src', Language['C++'].codemirror_mime_type
  end

  def test_wrap
    assert_equal false, Language['C'].wrap
    assert_equal true, Language['Markdown'].wrap
  end

  def test_extensions
    assert Language['LSL'].extensions.include?('.lsl')
    assert Language['Perl'].extensions.include?('.pl')
    assert Language['Python'].extensions.include?('.py')
    assert Language['Ruby'].extensions.include?('.rb')
    assert Language['SuperCollider'].extensions.include?('.scd')
  end

  def test_eql
    assert Language['Ruby'].eql?(Language['Ruby'])
    assert !Language['Ruby'].eql?(Language['Python'])
  end

  def test_by_type
    assert !Language.by_type(:prose).nil?
  end

  def test_all_languages_have_grammars
    scopes = YAML.load(File.read(File.expand_path("../../grammars.yml", __FILE__))).values.flatten
    missing = Language.all.reject { |language| language.tm_scope == "none" || scopes.include?(language.tm_scope) }
    message = "The following languages' scopes are not listed in grammars.yml. Please add grammars for all new languages.\n"
    message << "If no grammar exists for a language, mark the language with `tm_scope: none` in lib/linguist/languages.yml.\n"

    width = missing.map { |language| language.name.length }.max
    message << missing.map { |language| sprintf("%-#{width}s %s", language.name, language.tm_scope) }.sort.join("\n")
    assert missing.empty?, message
  end

  def test_all_languages_have_type
    missing = Language.all.select { |language| language.type.nil? }
    message = "The following languages do not have a type listed in grammars.yml. Please add types for all new languages.\n"

    width = missing.map { |language| language.name.length }.max
    message << missing.map { |language| sprintf("%-#{width}s", language.name) }.sort.join("\n")
    assert missing.empty?, message
  end

  def test_all_languages_have_a_language_id_set
    missing = Language.all.select { |language| language.language_id.nil? }

    message = "The following languages do not have a language_id listed in languages.yml. Please add language_id fields for all new languages.\n"
    missing.each { |language| message << "#{language.name}\n" }
    assert missing.empty?, message
  end

  def test_all_languages_have_a_valid_id
    invalid = Language.all.select { |language| language.language_id < 0 || language.language_id >= (2**31 - 1) }

    message = "The following languages do not have a valid language_id. Please use script/set-language-ids --update as per the contribution guidelines.\n"
    invalid.each { |language| message << "#{language.name}\n" }
    assert invalid.empty?, message
  end

  def test_all_language_id_are_unique
    duplicates = Language.all.group_by{ |language| language.language_id }.select { |k, v| v.size > 1 }.map(&:first)

    message = "The following language_id are used several times in languages.yml. Please use script/set-language-ids --update as per the contribution guidelines.\n"
    duplicates.each { |language_id| message << "#{language_id}\n" }
    assert duplicates.empty?, message
  end

  def test_all_languages_have_a_valid_ace_mode
    ace_fixture_path = File.join('test', 'fixtures', 'ace_modes.json')
    skip("No ace_modes.json file") unless File.exist?(ace_fixture_path)

    ace_github_modes = Yajl.load(File.read(ace_fixture_path))
    existing_ace_modes = ace_github_modes.map do |ace_github_mode|
      File.basename(ace_github_mode["name"], ".js") if ace_github_mode["name"]  !~ /_highlight_rules|_test|_worker/
    end.compact.uniq.sort.map(&:downcase)

    missing = Language.all.reject { |language| language.ace_mode == "text" || existing_ace_modes.include?(language.ace_mode) }
    message = "The following languages do not have an Ace mode listed in languages.yml. Please add an Ace mode for all new languages.\n"
    message << "If no Ace mode exists for a language, mark the language with `ace_mode: text` in lib/linguist/languages.yml.\n"

    width = missing.map { |language| language.name.length }.max
    message << missing.map { |language| sprintf("%-#{width}s %s", language.name, language.ace_mode) }.sort.join("\n")
    assert missing.empty?, message
  end

  def test_codemirror_modes_present
    Language.all.each do |language|
      if language.codemirror_mode || language.codemirror_mime_type
        assert language.codemirror_mode, "#{language.inspect} missing CodeMirror mode"
        assert language.codemirror_mime_type, "#{language.inspect} missing CodeMirror MIME mode"
      end
    end
  end

  def test_valid_codemirror_mode
    Language.all.each do |language|
      if mode = language.codemirror_mode
        assert File.exist?(File.expand_path("../../vendor/CodeMirror/mode/#{mode}", __FILE__)), "#{mode} isn't a valid CodeMirror mode"
      end
    end
  end

  def test_codemirror_mode_and_mime_defined_by_meta_mapping
    meta = File.read(File.expand_path("../../vendor/CodeMirror/mode/meta.js", __FILE__))
    Language.all.each do |language|
      next unless language.codemirror_mode && language.codemirror_mime_type
      assert meta.match(/^.+#{Regexp.escape(language.codemirror_mime_type)}.+#{Regexp.escape(language.codemirror_mode)}.+$/), "#{language.inspect}: #{language.codemirror_mime_type} not defined under #{language.codemirror_mode}"
    end
  end

  def test_codemirror_mime_declared_in_mode_file
    Language.all.each do |language|
      next unless language.codemirror_mode && language.codemirror_mime_type
      filename = File.expand_path("../../vendor/CodeMirror/mode/#{language.codemirror_mode}/#{language.codemirror_mode}.js", __FILE__)
      assert File.exist?(filename), "#{filename} does not exist"
      assert File.read(filename).match(language.codemirror_mime_type), "#{language.inspect}: #{language.codemirror_mime_type} not defined in #{filename}"
    end
  end

  def test_all_popular_languages_exist
    popular = YAML.load(File.read(File.expand_path("../../lib/linguist/popular.yml", __FILE__)))

    missing = popular - Language.all.map(&:name)
    message = "The following languages are listed in lib/linguist/popular.yml but not in lib/linguist/languages.yml.\n"
    message << missing.sort.join("\n")
    assert missing.empty?, message
  end

  def test_no_unused_colours
    Language.all.each do |language|
      next unless language.type == :data || language.type == :prose ||
        language.group.to_s != language.name
      assert !language.color, "Unused colour assigned to #{language.name}"
    end
  end

  def test_non_crash_on_comma
    assert_nil Language[',']
  end
end


text:
<?php

namespace ContactBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class DefaultController extends Controller {
    /**
     * @Route("/", name="contact")
     */
    public function indexAction() {
        return $this->render('ContactBundle:Default:index.html.twig');
    }
}


text:
package aws

import (
	"context"
	"testing"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/golang/mock/gomock"

	awsMock "github.com/themotion/ladder/mock/aws"
	"github.com/themotion/ladder/mock/aws/sdk"
)

func TestCWMetricCorrectCreation(t *testing.T) {
	tests := []struct {
		region     string
		metricName string
		namespace  string
		statistic  string
		unit       string
		offset     string
		dimensions []interface{}

		wantOffset time.Duration
	}{
		{
			"us-west-2", "CPUReservation", "AWS/ECS", "Maximum", "Percent", "0s",
			[]interface{}{
				map[interface{}]interface{}{cwDimensionsNameOpt: "ClusterName", cwDimensionsValueOpt: "slok-ECSCluster1-15OBYPKBNXIO6"},
			},
			0 * time.Second,
		},
		{
			"eu-west-1", "DiskReadBytes", "AWS/EC2", "Minimum", "Bytes", "-1m",
			[]interface{}{
				map[interface{}]interface{}{cwDimensionsNameOpt: "InstanceId", cwDimensionsValueOpt: "i-003efbc77add1544a"},
				map[interface{}]interface{}{cwDimensionsNameOpt: "InstanceType", cwDimensionsValueOpt: "t2.micro"},
			},
			-1 * time.Minute,
		},
		{
			"eu-west-1", "DiskReadBytes", "AWS/EC2", "Minimum", "Bytes", "-30s",
			[]interface{}{},
			-30 * time.Second,
		},
	}

	for _, test := range tests {
		opts := map[string]interface{}{
			cwAwsRegionOpt:  test.region,
			cwMetricNameOpt: test.metricName,
			cwNamespaceOpt:  test.namespace,
			cwStatisticOpt:  test.statistic,
			cwUnitOpt:       test.unit,
			cwDimensionsOpt: test.dimensions,
			cwTimeOffsetOpt: test.offset,
		}

		c, err := NewCWMetric(context.TODO(), opts)
		if err != nil {
			t.Fatalf("\n- %+v\n  Creation shouldn't give error: %v", test, err)
		}

		if aws.StringValue(c.session.Config.Region) != test.region {
			t.Errorf("\n- %+v\n  Wrong parameters loaded on object, want: %v; got %v", test, test.region, aws.StringValue(c.session.Config.Region))
		}

		if c.metricName != test.metricName {
			t.Errorf("\n- %+v\n  Wrong parameters loaded on object, want: %v; got %v", test, test.metricName, c.metricName)
		}

		if c.namespace != test.namespace {
			t.Errorf("\n- %+v\n  Wrong parameters loaded on object, want: %v; got %v", test, test.namespace, c.namespace)
		}

		if c.statistic != test.statistic {
			t.Errorf("\n- %+v\n  Wrong parameters loaded on object, want: %v; got %v", test, test.statistic, c.statistic)
		}

		if c.unit != test.unit {
			t.Errorf("\n- %+v\n  Wrong parameters loaded on object, want: %v; got %v", test, test.unit, c.unit)
		}

		if c.offset != test.wantOffset {
			t.Errorf("\n- %+v\n  Wrong parameters loaded on object, want: %v; got %v", test, test.wantOffset, c.offset)
		}

		if len(c.dimensions) != len(test.dimensions) {
			t.Errorf("\n- %+v\n  Wrong parameters loaded on object length, want: %v; got %v", test, len(test.dimensions), len(c.dimensions))
		}

		for i, d := range test.dimensions {
			n := d.(map[interface{}]interface{})[cwDimensionsNameOpt]
			v := d.(map[interface{}]interface{})[cwDimensionsValueOpt]

			if c.dimensions[i].name != n {
				t.Errorf("\n- %+v\n  Wrong parameters loaded on object, want: %v; got %v", test, n, c.dimensions[i].name)
			}
			if c.dimensions[i].value != v {
				t.Errorf("\n- %+v\n  Wrong parameters loaded on object, want: %v; got %v", test, v, c.dimensions[i].value)
			}
		}
	}
}

func TestCWMetricWrongParameterCreation(t *testing.T) {
	tests := []struct {
		region     string
		metricName string
		namespace  string
		statistic  string
		unit       string
		offset     string
		dimensions []interface{}
	}{
		// Missing params
		{metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "Maximum", unit: "Percent", offset: "-30s", dimensions: []interface{}{}},
		{region: "us-west-2", namespace: "AWS/ECS", statistic: "Maximum", unit: "Percent", offset: "-30s", dimensions: []interface{}{}},
		{region: "us-west-2", metricName: "CPUReservation", statistic: "Maximum", unit: "Percent", offset: "-30s", dimensions: []interface{}{}},
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", unit: "Percent", offset: "-30s", dimensions: []interface{}{}},
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "Maximum", offset: "-30s", dimensions: []interface{}{}},
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "Maximum", unit: "Percent", dimensions: []interface{}{}},

		// wrong params
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "Maximun", unit: "Percent", offset: "-30s", dimensions: []interface{}{}},
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "Max", unit: "Percent", offset: "-30s", dimensions: []interface{}{}},
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "wrong", unit: "Percent", offset: "-30s", dimensions: []interface{}{}},
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "Maximum", unit: "percent", offset: "-30s", dimensions: []interface{}{}},
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "Maximum", unit: "Percents", offset: "-30s", dimensions: []interface{}{}},
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "Maximum", unit: "wrong", offset: "-30s", dimensions: []interface{}{}},
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "Maximum", unit: "Percent", offset: "-30g", dimensions: []interface{}{}},

		// wrong types
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "Maximum", unit: "wrong", offset: "-30s", dimensions: []interface{}{1, 2, 3, 4}},
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "Maximum", unit: "wrong", offset: "-30s", dimensions: nil},
		{region: "us-west-2", metricName: "CPUReservation", namespace: "AWS/ECS", statistic: "Maximum", unit: "Percent", offset: "30s", dimensions: []interface{}{}},
		{
			region:     "us-west-2",
			metricName: "CPUReservation",
			namespace:  "AWS/ECS",
			statistic:  "Maximum",
			unit:       "wrong",
			dimensions: []interface{}{
				map[interface{}]interface{}{
					1: 2,
					2: 3,
				},
			},
		},
	}

	for _, test := range tests {
		opts := map[string]interface{}{
			cwAwsRegionOpt:  test.region,
			cwMetricNameOpt: test.metricName,
			cwNamespaceOpt:  test.namespace,
			cwStatisticOpt:  test.statistic,
			cwUnitOpt:       test.unit,
			cwDimensionsOpt: test.dimensions,
			cwTimeOffsetOpt: test.offset,
		}

		_, err := NewCWMetric(context.TODO(), opts)
		if err == nil {
			t.Fatalf("\n- %+v\n  Creation should give error, it didn't", test)
		}

	}
}

func TestCWMetricGather(t *testing.T) {
	tests := []struct {
		metric     float64
		wantMetric int64
	}{
		{1000, 1000},
		{1000000, 1000000},
		{9.45, 9},
		{48.9, 48},
	}

	for _, test := range tests {

		opts := map[string]interface{}{
			cwAwsRegionOpt:  "us-west-2",
			cwMetricNameOpt: "CPUReservation",
			cwNamespaceOpt:  "AWS/ECS",
			cwStatisticOpt:  "Maximum",
			cwUnitOpt:       "Bytes",
			cwDimensionsOpt: []interface{}{},
			cwTimeOffsetOpt: "0s",
		}

		// Create mock for AWS API
		ctrl := gomock.NewController(t)
		defer ctrl.Finish()
		mockCWMetric := sdk.NewMockCloudWatchAPI(ctrl)
		c, err := NewCWMetric(context.TODO(), opts)
		c.client = mockCWMetric

		// Set our mock desired result
		awsMock.MockGetMetricStatistics(t, mockCWMetric, test.metric, c.statistic, 1)

		if err != nil {
			t.Fatalf("\n- %+v\n  Creation shouldn't give error: %v", test, err)
		}

		res, err := c.Gather(context.TODO())
		if err != nil {
			t.Errorf("\n- %+v\n  Gathering shouldn't give error: %v", test, err)
		}

		if res.Q != test.wantMetric {
			t.Errorf("\n- %+v\n  Gathered quantity doesn't look good, got: %d want: %d", test, res.Q, test.wantMetric)

		}
	}
}

func TestCWMetricGatherWrong(t *testing.T) {
	times := 10

	for i := 0; i < times; i++ {

		opts := map[string]interface{}{
			cwAwsRegionOpt:  "us-west-2",
			cwMetricNameOpt: "CPUReservation",
			cwNamespaceOpt:  "AWS/ECS",
			cwStatisticOpt:  "Maximum",
			cwUnitOpt:       "Bytes",
			cwDimensionsOpt: []interface{}{},
			cwTimeOffsetOpt: "0s",
		}

		// Create mock for AWS API
		ctrl := gomock.NewController(t)
		defer ctrl.Finish()
		mockCWMetric := sdk.NewMockCloudWatchAPI(ctrl)
		c, err := NewCWMetric(context.TODO(), opts)
		c.client = mockCWMetric

		// Set our mock desired result
		awsMock.MockGetMetricStatisticsError(t, mockCWMetric)

		if err != nil {
			t.Fatalf("\n-  Creation shouldn't give error: %v", err)
		}

		_, err = c.Gather(context.TODO())
		if err == nil {
			t.Errorf("\n-  Gathering should give error, it didn't")
		}
	}
}

func TestCWMetricGatherMultipleMessages(t *testing.T) {
	times := 10

	for i := 2; i < times+2; i++ {

		opts := map[string]interface{}{
			cwAwsRegionOpt:  "us-west-2",
			cwMetricNameOpt: "CPUReservation",
			cwNamespaceOpt:  "AWS/ECS",
			cwStatisticOpt:  "Maximum",
			cwUnitOpt:       "Bytes",
			cwDimensionsOpt: []interface{}{},
			cwTimeOffsetOpt: "0s",
		}

		// Create mock for AWS API
		ctrl := gomock.NewController(t)
		defer ctrl.Finish()
		mockCWMetric := sdk.NewMockCloudWatchAPI(ctrl)
		c, err := NewCWMetric(context.TODO(), opts)
		c.client = mockCWMetric

		// Set our mock desired result
		awsMock.MockGetMetricStatistics(t, mockCWMetric, 0, "Sum", i)

		if err != nil {
			t.Fatalf("\n-  Creation shouldn't give error: %v", err)
		}

		_, err = c.Gather(context.TODO())
		if err == nil {
			t.Errorf("\n-  Gathering should give error, it didn't")
		}
	}
}


text:
module Caprese
  module Adapter
    class JsonApi
      # {http://jsonapi.org/format/#document-jsonapi-object Jsonapi Object}

      # toplevel_jsonapi
      # definition:
      #   JSON Object
      #
      # properties:
      #   version : String
      #   meta
      #
      # description:
      #   An object describing the server's implementation
      # structure:
      #   {
      #     version: ActiveModelSerializers.config.jsonapi_version,
      #     meta: ActiveModelSerializers.config.jsonapi_toplevel_meta
      #   }.reject! { |_, v| v.blank? }
      # prs:
      #   https://github.com/rails-api/active_model_serializers/pull/1050
      module Jsonapi
        module_function

        def add!(hash)
          hash.merge!(object) if include_object?
        end

        def include_object?
          ActiveModelSerializers.config.jsonapi_include_toplevel_object
        end

        # TODO: see if we can cache this
        def object
          object = {
            jsonapi: {
              version: ActiveModelSerializers.config.jsonapi_version,
              meta: ActiveModelSerializers.config.jsonapi_toplevel_meta
            }
          }
          object[:jsonapi].reject! { |_, v| v.blank? }

          object
        end
      end
    end
  end
end


text:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_enabled="false">
        <shape>
            <corners android:radius="5dp" />

            <solid android:color="#CBC6C6" />

            <stroke android:width="0.5dp"
                 android:color="@color/white" />
        </shape>
    </item>

    <item android:state_enabled="true"
         android:state_pressed="false">
        <shape>
            <corners android:radius="5dp" />

            <solid android:color="#FAB724" />

            <stroke android:width="0.5dp"
                 android:color="#CBC6C6" />
        </shape>
    </item>

    <item android:state_enabled="true"
         android:state_pressed="true">
        <shape>
            <corners android:radius="5dp" />

            <solid android:color="#CBC6C6" />

            <stroke android:width="0.5dp"
                 android:color="#FAB724" />
        </shape>
    </item>

</selector>


text:
package com.loopbook.cuhk_loopbook;

import java.util.*;

import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.net.Uri;

import android.content.Intent;
import android.content.Context;

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        boolean firstRun = (savedInstanceState == null && isFirstRun(this));

        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            BookFragment bookFrag = new BookFragment();
            if (firstRun) {
                Bundle bundle = new Bundle();
                bundle.putBoolean("firstRun", true);
                bookFrag.setArguments(bundle);
            }

            getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragment_placeholder, bookFrag)
                .commit();
        }

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        if (firstRun) {
            setRunned();
            CheckSched.scheduleNotification(this);
            Toast.makeText(this, getString(R.string.first_run_msg), Toast.LENGTH_LONG).show();
            Intent myIntent1 = new Intent(this, Setting.class);
            startActivityForResult(myIntent1, 1);
        }
    }

    public static boolean isFirstRun(Context ctx) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
        return prefs.getBoolean("firstrun", true);
    }

    public void setRunned() {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putBoolean("firstrun", false);
        editor.commit();
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        BookFragment f = (BookFragment) getSupportFragmentManager()
                                          .findFragmentById(R.id.fragment_placeholder);
        f.refresh();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_settings:
                Intent myIntent1 = new Intent(this, Setting.class);
                startActivityForResult(myIntent1, 1);
                break;
            case R.id.action_about:
                Intent myIntent3 = new Intent(this, About.class);
                startActivity(myIntent3);
                break;
            case R.id.action_renew:
                /* after many despairing attempt to open chrome with POST
                 * method, I found that I can log in with GET method!!!
                 * be aware that this is less secure, but nobody cares
                 */
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
                String user_id = prefs.getString("user_id", "");
                String user_passwd = prefs.getString("user_passwd", "");
                String url = "https://m.library.cuhk.edu.hk/patroninfo?code=%s&pin=%s";
                url = String.format(url, user_id, user_passwd);
                Intent myIntent2 = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(url));
                startActivity(myIntent2);
                break;
            case R.id.action_refresh:
                BookFragment f = (BookFragment) getSupportFragmentManager()
                        .findFragmentById(R.id.fragment_placeholder);
                f.refresh();
                break;
        }
        return true;
    }
}


text:
package com.longluo.demo.jpush;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONObject;

import cn.jpush.android.api.JPushInterface;

/**
 * 自定义接收器
 * <p/>
 * 如果不定义这个 Receiver,则:
 * 1) 默认用户会打开主界面
 * 2) 接收不到自定义消息
 */
public class MyReceiver extends BroadcastReceiver {
    private static final String TAG = "JPush";

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle bundle = intent.getExtras();
        Log.d(TAG, "[MyReceiver] onReceive - " + intent.getAction() + ", extras: " + printBundle(bundle));

        if (JPushInterface.ACTION_REGISTRATION_ID.equals(intent.getAction())) {
            String regId = bundle.getString(JPushInterface.EXTRA_REGISTRATION_ID);
            Log.d(TAG, "[MyReceiver] 接收Registration Id : " + regId);
            //send the Registration Id to your server...

        } else if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {
            Log.d(TAG, "[MyReceiver] 接收到推送下来的自定义消息: " + bundle.getString(JPushInterface.EXTRA_MESSAGE));
            processCustomMessage(context, bundle);

        } else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(intent.getAction())) {
            Log.d(TAG, "[MyReceiver] 接收到推送下来的通知");
            int notifactionId = bundle.getInt(JPushInterface.EXTRA_NOTIFICATION_ID);
            Log.d(TAG, "[MyReceiver] 接收到推送下来的通知的ID: " + notifactionId);

        } else if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) {
            Log.d(TAG, "[MyReceiver] 用户点击打开了通知");

            //打开自定义的Activity
            Intent i = new Intent(context, TestActivity.class);
            i.putExtras(bundle);
            //i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
            context.startActivity(i);

        } else if (JPushInterface.ACTION_RICHPUSH_CALLBACK.equals(intent.getAction())) {
            Log.d(TAG, "[MyReceiver] 用户收到到RICH PUSH CALLBACK: " + bundle.getString(JPushInterface.EXTRA_EXTRA));
            //在这里根据 JPushInterface.EXTRA_EXTRA 的内容处理代码,比如打开新的Activity, 打开一个网页等..

        } else if (JPushInterface.ACTION_CONNECTION_CHANGE.equals(intent.getAction())) {
            boolean connected = intent.getBooleanExtra(JPushInterface.EXTRA_CONNECTION_CHANGE, false);
            Log.w(TAG, "[MyReceiver]" + intent.getAction() + " connected state change to " + connected);
        } else {
            Log.d(TAG, "[MyReceiver] Unhandled intent - " + intent.getAction());
        }
    }

    // 打印所有的 intent extra 数据
    private static String printBundle(Bundle bundle) {
        StringBuilder sb = new StringBuilder();
        for (String key : bundle.keySet()) {
            if (key.equals(JPushInterface.EXTRA_NOTIFICATION_ID)) {
                sb.append("\nkey:" + key + ", value:" + bundle.getInt(key));
            } else if (key.equals(JPushInterface.EXTRA_CONNECTION_CHANGE)) {
                sb.append("\nkey:" + key + ", value:" + bundle.getBoolean(key));
            } else {
                sb.append("\nkey:" + key + ", value:" + bundle.getString(key));
            }
        }
        return sb.toString();
    }

    //send msg to MainActivity
    private void processCustomMessage(Context context, Bundle bundle) {
        if (JPushDemoActivity.isForeground) {
            String message = bundle.getString(JPushInterface.EXTRA_MESSAGE);
            String extras = bundle.getString(JPushInterface.EXTRA_EXTRA);
            Intent msgIntent = new Intent(JPushDemoActivity.MESSAGE_RECEIVED_ACTION);
            msgIntent.putExtra(JPushDemoActivity.KEY_MESSAGE, message);
            if (!JPushUtil.isEmpty(extras)) {
                try {
                    JSONObject extraJson = new JSONObject(extras);
                    if (null != extraJson && extraJson.length() > 0) {
                        msgIntent.putExtra(JPushDemoActivity.KEY_EXTRAS, extras);
                    }
                } catch (JSONException e) {

                }

            }
            context.sendBroadcast(msgIntent);
        }
    }
}


text:
layout: post
title:  "100 Days of SwiftUI - Day 59"
date:   2019-12-24 22:30:01 +1300
categories: ohdos
---
According to the rules for taking part in [100 Days of SwiftUI](https://www.hackingwithswift.com/100/swiftui), as soon as I've finished each day, I have to post about it.

The topic for Day 59 was: Project 12, part 3.

This included a project wrap-up, a project review, and 3 challenges. Will get back to the challenges once I've caught up.


text:
import Helpers from '../../test-helpers';

import { DIRECTION } from 'mobiledoc-kit/utils/key';
const { FORWARD, BACKWARD } = DIRECTION;

const { module, test } = Helpers;

let { postEditor: { run } } = Helpers;
let { postAbstract: { buildFromText } } = Helpers;
const { editor: { retargetPosition } } = Helpers;

module('Unit: PostEditor: #deleteAtPosition');

let expectationGroups = [{
  name: 'single markup section',
  direction: BACKWARD,
  expectations: [
    ['abc|def', 'ab|def', 'middle'],
    ['abcdef|', 'abcde|', 'end'],
    ['|abcdef', '|abcdef', 'start'],

    ['ab *cd*| ef', 'ab *c*| ef', 'markup (right side)'],
    ['ab |*cd* ef', 'ab|*cd* ef', 'markup (left side)'],

    ['ab @| ef', 'ab | ef', 'atom (right side)'],
    ['ab |@ ef', 'ab|@ ef', 'atom (left side)']
  ]
}, {
  name: 'single markup section',
  direction: FORWARD,
  expectations: [
    ['abc|def', 'abc|ef', 'middle'],
    ['abcdef|', 'abcdef|', 'end'],
    ['|abcdef', '|bcdef', 'start'],

    ['ab *cd*| ef', 'ab *cd*|ef', 'markup (right side)'],
    ['ab |*cd* ef', 'ab |*d* ef', 'markup (left side)'],

    ['ab @| ef', 'ab @|ef', 'atom (right side)'],
    ['ab |@ ef', 'ab | ef', 'atom (left side)']
  ]
}, {
  name: 'across section boundary',
  direction: BACKWARD,
  expectations: [
    [['abc','|def'], 'abc|def', 'markup sections'],
    [['*abc*','|def'], '*abc*|def', 'markup sections with markup'],
    [['[abc]','|def'], ['[abc]|','def'], 'prev section is card'],
    [['abc','|[def]'], ['abc|','[def]'], 'cur section is card'],
    [['', '|abc'], ['|abc'], 'prev section is blank']
  ]
}, {
  name: 'across section boundary',
  direction: FORWARD,
  expectations: [
    [['abc|','def'], 'abc|def', 'markup sections'],
    [['*abc*|','def'], '*abc*|def', 'markup sections with markup'],
    [['[abc]|','def'], ['[abc]|','def'], 'cur section is card'],
    [['abc|','[def]'], ['abc|','[def]'], 'next section is card'],
    [['abc|', ''], ['abc|'], 'next section is blank']
  ]
}, {
  name: 'across list item boundary',
  direction: BACKWARD,
  expectations: [
    [['* abc','* |def'], ['* abc', '|def'], 'start of list item'],
    [['* abc','|def'], ['* abc|def'], 'into list item'],
    [['', '* |abc'], ['', '|abc'], 'prev blank section'],
  ]
}, {
  name: 'across list item boundary',
  direction: FORWARD,
  expectations: [
    [['* abc|','* def'], ['* abc|def'], 'item into item'],
    [['* abc|','def'], ['* abc|def'], 'item into markup'],
    [['abc|','* def'], ['abc|def'], 'markup into markup'],
  ]
}];

expectationGroups.forEach(({name, expectations, direction}) => {
  expectations.forEach(([before, after, msg]) => {
    let dir = direction === FORWARD ? 'forward' : 'backward';
    test(`${dir}: ${name}, "${before}" -> "${after}" (${msg})`, (assert) => {
      let { post, range: { head: position } } = buildFromText(before);
      let { post: expectedPost, range: { head: expectedPosition } } = buildFromText(after);

      position = run(post, postEditor => postEditor.deleteAtPosition(position, direction));
      expectedPosition = retargetPosition(expectedPosition, post);

      assert.postIsSimilar(post, expectedPost);
      assert.positionIsEqual(position, expectedPosition);
    });
  });
});


text:
/**
 * Runepage.js
 *
 * @description :: TODO: You might write a short summary of how this model works and what it represents here.
 * @docs        :: http://sailsjs.org/documentation/concepts/models-and-orm/models
 */

module.exports = {

    attributes: {
        id_lol: {
            type: 'integer'
        },
        name_lol: {
            type: 'string'
        },
        current_lol: {
            type: 'string'
        },
        summoner: {
            model: 'summoner'
        },
        slots: {
            collection: 'runpageslot',
            via: 'runepage'
        }
    }
};


text:
class Fruit < ActiveRecord::Base
  attr_accessible :name, :season_start_month, :season_start_day, :season_end_month, :season_end_day

  has_many :fruit_trees
  has_many :sites, :through => :fruit_trees

  validates :season_start_month, :presence => true,  :inclusion => { :in => MONTHS }
  validates :season_end_month, :presence => true, :inclusion => { :in => MONTHS }
  validates :season_start_day, :presence => true, :inclusion => { :in => (1..31).to_a }
  validates :season_end_day, :presence => true, :inclusion => { :in => (1..31).to_a }

end


text:
require "rb-inotify"

module VagrantPlugins
  module GatlingRsync
    class ListenLinux
      def initialize(paths, ignores, latency, logger, callback)
        @paths = paths
        @ignores = ignores
        @latency = latency
        @logger = logger
        @callback = callback
      end

      def run
        @logger.info("Listening via: rb-inotify on Linux.")

        notifier = INotify::Notifier.new
        @paths.keys.each do |path|
          notifier.watch(path, :modify, :create, :delete, :recursive) {}
        end

        loop do
          directories = Set.new
          begin
            loop do
              events = []
              events = Timeout::timeout(@latency) {
                notifier.read_events
              }
              events.each { |e| directories << e.absolute_name }
            end
          rescue Timeout::Error
            @logger.info("Breaking out of the loop at #{Time.now.to_s}.")
          end

          @logger.info("Detected changes to #{directories.inspect}.") unless directories.empty?

          @callback.call(@paths, @ignores, directories) unless directories.empty?
        end
      end
    end
  end
end


text: __author__ = 'Charles'


text:
from collections import OrderedDict

expected = [
    OrderedDict(
        [
            ("mediaType", "application/zip"),
            ("uri", u"elife-16996-supp-v1.zip"),
            ("filename", u"elife-16996-supp-v1.zip"),
            ("id", "SD1-data"),
            ("label", "All additional files"),
            (
                "caption",
                [
                    OrderedDict(
                        [
                            (
                                "text",
                                "Any figure supplements, source code, source data, videos or supplementary files associated with this article are contained within this zip.",
                            ),
                            ("type", "paragraph"),
                        ]
                    )
                ],
            ),
        ]
    )
]


text:
require 'active_support/all'

module MetOfficeAPI

  class ForecastHour

    attr_accessor :time_str

    def initialize mins_since_midnight, weather_code, temp, feels_like_temp
      @time_str = (Time.now.beginning_of_day + 60 * mins_since_midnight.to_i).strftime("%H:%M")
      @weather_code = weather_code
      @temp = temp
      @feels_like_temp = feels_like_temp
    end

    def weather_text
      WEATHER_TYPES.fetch(@weather_code)
    end

    def weather_image
      WEATHER_IMAGES.fetch(@weather_code)
    end

    def temp unit = nil
      unit ||= MetOfficeAPI::CELCIUS
      MetOfficeAPI::Util.return_temp_or_convert @temp, unit
    end

    def feels_like_temp unit = nil
      unit ||= MetOfficeAPI::CELCIUS
      MetOfficeAPI::Util.return_temp_or_convert @feels_like_temp, unit
    end

  end

end


text:
@implementation Item (HB)

- (NSInteger)left {
    NSArray *items = @(self.itemId).hb_itemsForItemId;
    NSArray *children = items.hb_idsForItems;

    return ({
        NSInteger count = self.count;
        for (NSNumber *idNumber in children) {
            if ([UserData isToggledItemId:idNumber.integerValue]) {
                count--;
            }
        }
        count;
    });
}

@end


text:
export default {
  errors: {
    blank: "can't blank",
    invalid: "generic invalid",
    email: {
      blank: "email can't be blank"
    }
  }
}