[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n"
  },
  {
    "path": "GameSDKBuildJarTool/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDKBuildJarTool/build.gradle",
    "content": "apply plugin: 'java-library'\napply plugin: 'idea'\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile files('libs/proguard.jar')\n}\n\n//解决控件台中文乱码问题\ntasks.withType(JavaCompile) {\n    options.encoding = \"UTF-8\"\n}\n\ntasks.withType(JavaCompile) {\n    compileTask -> compileTask.dependsOn tasks.findByName('idea')\n}\n\nsourceSets {\n    main {\n        resources {\n            srcDirs \"src/main/resources\"\n        }\n    }\n}\n\nsourceCompatibility = \"1.7\"\ntargetCompatibility = \"1.7\"\n\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/cmd/test/java/HelloWorld.java",
    "content": "package com.bzai.demo;\n\npublic class HelloWorld {\n\n    public static void main(String[] args){\n        System.out.println(\"hello world\");\n        test();\n    }\n\n    public static void test(){\n        TestA testA = new TestA();\n        testA.Test();\n    }\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/cmd/test/java/TestA.java",
    "content": "package com.bzai.demo;\n\npublic class TestA {\n\n    public String name = \"asdfa\";\n\n    public void Test(){\n        System.out.println(\"name:\"+name);\n    }\n\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/cmd/test/proguard/proguard_config.pro",
    "content": "\n-dontskipnonpubliclibraryclassmembers\n-dontshrink\n-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable\n-dontusemixedcaseclassnames\n-keepattributes SourceFile,LineNumberTable,*Annotation*,Signature,Deprecated,InnerClasses\n-keepparameternames\n-renamesourcefileattribute SourceFile\n-verbose\n\n-dontwarn android.support.v4.**\n\n# Keep names - Native method names. Keep all native class/method names.\n-keepclasseswithmembers,allowshrinking class * {\n    native <methods>;\n}\n\n\n\n\n\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/BuildJarTask.java",
    "content": "package com.bzai.gamesdk.build;\n\nimport com.android.manifmerger.ManifestMerger2;\nimport com.android.manifmerger.MergingReport;\nimport com.android.manifmerger.XmlDocument;\nimport com.android.utils.StdLogger;\nimport com.bzai.gamesdk.build.bean.ErrorMsg;\nimport com.bzai.gamesdk.build.bean.Project;\nimport com.bzai.gamesdk.build.tools.JavaTool;\nimport com.bzai.gamesdk.build.tools.ProGuardTool;\nimport com.bzai.gamesdk.build.tools.ServerTool;\nimport com.bzai.gamesdk.build.utils.FileUtils;\nimport com.bzai.gamesdk.build.utils.Utils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Files;\nimport java.nio.file.StandardOpenOption;\nimport java.util.List;\n\n/**\n * 混淆jarTask\n */\npublic class BuildJarTask implements Runnable{\n\n    @Override\n    public void run() {\n\n        //创建输出路径\n        String outputPath;\n        try {\n\n            Config.getInstance().loadConfig();\n            outputPath = Config.getInstance().getOutPutPath();\n            FileUtils.createDirectories(outputPath,true);\n\n        }catch (Exception e){\n            e.printStackTrace();\n            return;\n        }\n\n        //同步资源\n        List<Project> projectList;\n        try {\n            projectList = Config.getInstance().getProject();\n            if (null == projectList || projectList.isEmpty()){\n                System.out.println(\"project list is empty\");\n                return;\n            }\n\n            String workspacePath = outputPath + File.separator + \"workspace\";\n            FileUtils.createDirectory(workspacePath);\n\n            ServerTool.DownServerResource(projectList,workspacePath);\n\n        }catch (Exception e){\n            e.printStackTrace();\n            return;\n        }\n\n        //buildJar\n        String jarName = Config.getInstance().getJarName();\n        String jarVersion = Config.getInstance().getJarVersion();\n        String buildJar = jarName + \"_\" + jarVersion;\n\n        String jarOutputPath = outputPath + File.separator + \"jar_out\";\n        String jarFileOutputPath = jarOutputPath + File.separator + buildJar + \".jar\";\n        ErrorMsg errorMsg = buildJar(projectList, jarFileOutputPath);\n        if (errorMsg.code != Utils.OK){\n            System.out.println(\"Tips:\" + errorMsg.getMessage() + \"\\n\");\n            errorMsg.e.printStackTrace();\n            return;\n        }\n\n\n        //build resource file.\n        String resourceOutputPath = outputPath + File.separator + \"resource\";\n        try{\n            FileUtils.createDirectory(resourceOutputPath);\n            buildResourceFile(resourceOutputPath, projectList);\n        }catch (Exception e){\n            e.printStackTrace();\n            return;\n        }\n\n        System.out.println(\"\\n\");\n        System.out.println(\"SDK输出路径：\" + jarFileOutputPath);\n        System.out.println(\"资源文件输出路径：\" + resourceOutputPath);\n\n    }\n\n\n    /**\n     * 编译生成混淆jar包过程\n     * @param projectList 工程配置\n     * @param jarOutputPath jar包输出路径\n     * @return\n     */\n    private ErrorMsg buildJar(List<Project> projectList, String jarOutputPath){\n\n        File jarFile = new File(jarOutputPath);\n        String outputPath = jarFile.getParent();\n\n        //创建一个Temp工程\n        Project tmpBuildProject = new Project();\n        String projectName = \"tmpBuildProject\";\n        String tmpBuildProjectPath = outputPath + File.separator + projectName;\n        tmpBuildProject.setName(projectName);\n        tmpBuildProject.setPath(tmpBuildProjectPath);\n\n        //创建temp工程目录，Java 和 libs\n        String projectSrcPath = tmpBuildProjectPath + File.separator + Project.JAVA_RELATIVE_PATH;\n        try{\n            FileUtils.createDirectoriesIfNonExists(outputPath);\n            FileUtils.createDirectoriesIfNonExists(tmpBuildProjectPath);\n            FileUtils.createDirectoriesIfNonExists(projectSrcPath);\n        }catch (Exception e){\n            return new ErrorMsg(Utils.ERROR, e.getMessage(), e);\n        }\n\n        //将各个项目的java文件下的源文件拷贝到 tmpBuildProject 的src文件下。\n        try{\n            for (Project project : projectList){\n                String tmpProjectSrcPath = project.getPath() + File.separator + Project.JAVA_RELATIVE_PATH;\n                if (FileUtils.exists(tmpProjectSrcPath)){\n                    FileUtils.copy(tmpProjectSrcPath, projectSrcPath, false);\n                }\n            }\n        }catch (Exception e){\n            return new ErrorMsg(Utils.ERROR, e.getMessage(), e);\n        }\n\n        // .java and .jar compile to .class\n        String classPath = getClasspath(tmpBuildProject,projectList);\n        String classFilesOutputPath = tmpBuildProjectPath + File.separator + \"classes\";\n        try {\n            FileUtils.createDirectory(classFilesOutputPath);\n            JavaTool.compile(projectSrcPath, classPath, classFilesOutputPath, null);\n\n        }catch (Exception e){\n            return new ErrorMsg(Utils.ERROR, \"构建SDK-编译.java to .class出错\", e);\n        }\n\n        // .class compile to .jar\n        String noProguardJar = outputPath + File.separator + \"no_proguard.jar\";\n        try{\n            JavaTool.classFilesToJar(classFilesOutputPath, noProguardJar, null);\n        }catch (Exception e){\n            return new ErrorMsg(Utils.ERROR, \"构建SDK-编译.class打包jar出错\", e);\n        }\n\n        //proguard jar\n        try{\n\n            String mapping = outputPath + File.separator + \"proguard_mapping.txt\";\n            String logging = outputPath + File.separator + \"proguard_log.txt\";\n            String root_path = System.getProperty(\"user.dir\");\n            String proJarPath = root_path + File.separator + \"GameSDKBuildJarTool\" + File.separator + \"libs\"\n                                + File.separator + \"proguard.jar\";\n            String proguardConfigFilePath = Config.getInstance().get_config_file_path(\"proguard_config.pro\");\n            ProGuardTool.run(proJarPath, noProguardJar, classPath, proguardConfigFilePath, mapping, logging, jarOutputPath);\n\n        }catch (Exception e){\n            return new ErrorMsg(Utils.ERROR, \"构建SDK-混淆jar出错\", e);\n        }\n\n        return new ErrorMsg(Utils.OK, \"ok\");\n    }\n\n    /**\n     * 合并工程资源文件过程\n     * @param resourceOutputPath\n     * @param projectList\n     * @throws IOException\n     * @throws InterruptedException\n     * @throws ManifestMerger2.MergeFailureException\n     */\n    public void buildResourceFile(String resourceOutputPath, List<Project> projectList)\n            throws IOException, InterruptedException, ManifestMerger2.MergeFailureException {\n\n        /*copy libs,assets,res to library project*/\n        String libsPath = resourceOutputPath + File.separator + Project.LIBS_FILE;\n        String assetsPath = resourceOutputPath + File.separator + Project.ASSETS_FILE;\n        final String resPath = resourceOutputPath + File.separator + Project.RES_FILE;\n        String jniLibsFilePath = resourceOutputPath + File.separator + Project.JNI_LIBS_FILE;\n        for (Project project : projectList){\n            /*copy assets*/\n            String projectAssetsPath = project.getPath() + File.separator + Project.ASSETS_RELATIVE_PATH;\n            if (FileUtils.exists(projectAssetsPath)){\n                FileUtils.createDirectoryIfNonExists(assetsPath);\n                FileUtils.copy(projectAssetsPath, assetsPath, false);\n            }\n\n            /*copy jni libs*/\n            String projectJniLibsPath = project.getPath() + File.separator + Project.JNI_LIBS_RELATIVE_PATH;\n            if (FileUtils.exists(projectJniLibsPath)){\n                FileUtils.createDirectoryIfNonExists(jniLibsFilePath);\n                FileUtils.copy(projectJniLibsPath, jniLibsFilePath, false);\n            }\n\n            /*copy libs*/\n            String projectLibsPath = project.getPath() + File.separator + Project.LIBS_RELATIVE_PATH;\n            if (FileUtils.exists(projectLibsPath)){\n                FileUtils.createDirectoryIfNonExists(libsPath);\n                FileUtils.copy(projectLibsPath, libsPath, false);\n            }\n\n            /*copy res*/\n            final String projectResPath = project.getPath() + File.separator + Project.RES_RELATIVE_PATH;\n            if (FileUtils.exists(projectResPath)){\n                FileUtils.createDirectoryIfNonExists(resPath);\n                FileUtils.copy(projectResPath, resPath, false);\n            }\n\n            //manifest merge\n            String projectManifestPath = project.getPath() + File.separator + Project.ANDROID_MANIFEST_RELATIVE_PATH;\n            String mainManifestPath = resourceOutputPath + File.separator + Project.ANDROID_MANIFEST_FILE;\n            if (!FileUtils.exists(mainManifestPath)){\n                FileUtils.copy(projectManifestPath, mainManifestPath, true);\n            }else{\n                StdLogger stdLogger = new StdLogger(StdLogger.Level.ERROR);\n                ManifestMerger2.Invoker manifestMerger = ManifestMerger2.newMerger(new File(mainManifestPath),\n                        stdLogger, ManifestMerger2.MergeType.APPLICATION);\n                manifestMerger.addLibraryManifest(new File(projectManifestPath));\n                manifestMerger.withFeatures(ManifestMerger2.Invoker.Feature.REMOVE_TOOLS_DECLARATIONS);\n                MergingReport mergingReport = manifestMerger.merge();\n                XmlDocument xmlDocument = mergingReport.getMergedDocument().get();\n\n                Files.write(FileSystems.getDefault().getPath(mainManifestPath),\n                        xmlDocument.prettyPrint().getBytes(\"UTF-8\"), StandardOpenOption.WRITE);\n                switch (mergingReport.getResult()) {\n                    case WARNING:\n                        // fall through since these are just warnings.\n                        mergingReport.log(stdLogger);\n                        break;\n                    case SUCCESS:\n                        break;\n                    case ERROR:\n                        mergingReport.log(stdLogger);\n                        throw new RuntimeException(mergingReport.getReportString());\n                    default:\n                        throw new RuntimeException(\"Unhandled result type : \"\n                                + mergingReport.getResult());\n                }\n            }\n        }\n\n//        /*如果jar文件中存在assets资源文件，需要jar中的将assets文件提取出来*/\n//        List<String> jarFileList = FileUtils.getFileList(libsPath, \".jar\");\n//        for (String jarFilePath : jarFileList){\n//            File jarFile = new File(jarFilePath);\n//            String unzipToFilePath = libsPath +File.separator\n//                    + jarFile.getName().substring(0, jarFile.getName().lastIndexOf(\".\"));\n//            Utils.jarFileUnzip(jarFilePath, unzipToFilePath);\n//            String assetsFilePath = unzipToFilePath + File.separator + Project.ASSETS_FILE;\n//            if (FileUtils.exists(assetsFilePath)){\n//                String outputPathAssetsPath = resourceOutputPath + File.separator + Project.ASSETS_FILE;\n//                FileUtils.createDirectoryIfNonExists(outputPathAssetsPath);\n//                FileUtils.move(assetsFilePath, outputPathAssetsPath, false);\n//\n//                /*删除原来的jar，重新压缩一个删除assets的jar文件*/\n//                FileUtils.delete(jarFilePath);\n//                JavaTool.classFilesToJar(unzipToFilePath, jarFilePath, null);\n//\n//                FileUtils.delete(unzipToFilePath);\n//            }else{\n//                FileUtils.delete(unzipToFilePath);\n//            }\n//        }\n    }\n\n    private String getClasspath(Project project, List<Project> projectList){\n\n        String classpath = \"\";\n\n        //获取工程jar路径\n        for (Project dependProject : projectList){\n            String projectPath = dependProject.getPath();\n            String projectLibsPath = projectPath + File.separator + Project.LIBS_RELATIVE_PATH;\n            if (FileUtils.exists(projectLibsPath)){\n                String jarPathSet = Utils.getJarPathSet(projectLibsPath,Utils.OS_SEMICOLON);\n                if (!Utils.isEmpty(jarPathSet)){\n                    if (!Utils.isEmpty(classpath)){\n                        classpath = classpath + Utils.OS_SEMICOLON;\n                    }\n                    classpath = classpath + jarPathSet;\n                }\n            }\n        }\n\n        //获取工程源码路径\n        String projectJavaPath = project.getPath() + File.separator + Project.JAVA_RELATIVE_PATH;\n        if (FileUtils.exists(projectJavaPath)){\n            if (!Utils.isEmpty(classpath)){\n                classpath = classpath + Utils.OS_SEMICOLON;\n            }\n            classpath = classpath + projectJavaPath;\n        }\n\n        //获取SDK版本 android.jar 路径\n        if (!Utils.isEmpty(classpath)){\n            classpath = classpath + Utils.OS_SEMICOLON;\n        }\n        classpath = classpath + getMinSdkVersionPath();\n        return classpath;\n    }\n\n    /**\n     * 获取Android sdk jar的存放路径\n     *\n     * @return\n     */\n    private String getMinSdkVersionPath(){\n        String androidSDKPath = Config.getInstance().getAndroidSdkPath();\n        String androidJarPath = androidSDKPath + File.separator +\"platforms\"\n                + File.separator+ Config.getInstance().getTargetSdkVersion()+File.separator+\"android.jar\";\n        return androidJarPath;\n    }\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/Config.java",
    "content": "package com.bzai.gamesdk.build;\n\nimport com.bzai.gamesdk.build.bean.Project;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.Set;\n\n/**\n * 配置文件\n */\npublic class Config {\n\n    /**\n     * android SDK 路径\n     */\n    public String androidSdkPath;\n\n    /**\n     * android target 版本\n     */\n    public String targetSdkVersion;\n\n    /**\n     * 输出jar包的名称\n     */\n    public String jarName;\n\n    /**\n     * 输出jar包的版本号\n     */\n    public String jarVersion;\n\n    /**\n     * 输出jar的路径\n     */\n    public String outPutPath;\n\n    private static Config mConfig;\n    private static byte[] syncObj = new byte[0];\n\n    private Config(){\n    }\n\n    public static Config getInstance(){\n        if (null == mConfig){\n            synchronized (syncObj){\n                if (null == mConfig){\n                    mConfig = new Config();\n                }\n            }\n        }\n        return mConfig;\n    }\n\n    /**\n     * 加载配置文件\n     */\n    public void loadConfig() throws IOException{\n\n          //这段代码在IDEA中可以正常读取到\n//        Properties properties = new Properties();\n//        URL url = ClassLoader.getSystemClassLoader().getResource(\"config\");\n//        properties.load(new FileInputStream(url.getFile()));\n\n        String config_path = get_config_file_path(\"config\");\n        Properties properties = new Properties();\n        properties.load(new FileInputStream(config_path));\n\n        androidSdkPath = properties.getProperty(\"androidSdkPath\");\n        targetSdkVersion = properties.getProperty(\"targetSdkVersion\");\n        jarName = properties.getProperty(\"jarName\");\n        jarVersion = properties.getProperty(\"jarVersion\");\n        outPutPath = properties.getProperty(\"outPutPath\");\n    }\n\n    /**\n     * 解析配置文件的工程配置\n     * @return\n     * @throws IOException\n     */\n    public List<Project> getProject() throws IOException{\n\n//        Properties properties = new Properties();\n//        URL url = ClassLoader.getSystemClassLoader().getResource(\"project_list\");\n//        properties.load(new FileInputStream(url.getFile()));\n\n        String config_path = get_config_file_path(\"project_list\");\n        Properties properties = new Properties();\n        properties.load(new FileInputStream(config_path));\n\n        List<Project> projectList = new ArrayList<>();\n        Set<Object> keySet = properties.keySet();\n        for (Object key : keySet){\n            String keyStr = (String) key;\n            String value = properties.getProperty(keyStr);\n            value = value.replaceAll(\" \",\"\");\n            String[] valueList = value.split(\",\");\n            int revision = 0;\n            if (valueList[0].matches(\"[0-9]*\")){\n                revision = Integer.parseInt(valueList[0]);\n            }\n            Project project = new Project();\n            project.setVersion(revision);\n            project.setName(keyStr);\n            project.setUrl(valueList[1]);\n            projectList.add(project);\n        }\n        return projectList;\n    }\n\n    public String get_config_file_path(String file_name){\n\n        //在AndroidStudio中用绝对路径读取\n        //但是要在Run/Debug configurations 配置Working directory工作目录路径\n        String root_path = System.getProperty(\"user.dir\");\n        String file_path = root_path + File.separator + \"GameSDKBuildJarTool\" +\n                File.separator + \"src\"  + File.separator + \"main\" +\n                File.separator + \"resources\"  + File.separator + file_name;\n//        System.out.println(file_path);\n        return file_path;\n    }\n\n    public String getAndroidSdkPath() {\n        return androidSdkPath;\n    }\n\n    public void setAndroidSdkPath(String androidSdkPath) {\n        this.androidSdkPath = androidSdkPath;\n    }\n\n    public String getTargetSdkVersion() {\n        return targetSdkVersion;\n    }\n\n    public void setTargetSdkVersion(String targetSdkVersion) {\n        this.targetSdkVersion = targetSdkVersion;\n    }\n\n    public String getJarName() {\n        return jarName;\n    }\n\n    public void setJarName(String jarName) {\n        this.jarName = jarName;\n    }\n\n    public String getJarVersion() {\n        return jarVersion;\n    }\n\n    public void setJarVersion(String jarVersion) {\n        this.jarVersion = jarVersion;\n    }\n\n    public String getOutPutPath() {\n        return outPutPath;\n    }\n\n    public void setOutPutPath(String outPutPath) {\n        this.outPutPath = outPutPath;\n    }\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/Main.java",
    "content": "package com.bzai.gamesdk.build;\n\npublic class Main {\n\n    public static void main(String[] args){\n        new Thread(new BuildJarTask()).start();\n    }\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/bean/ErrorMsg.java",
    "content": "package com.bzai.gamesdk.build.bean;\n\n/**\n * 描述打包结果\n */\npublic class ErrorMsg {\n\n    public int code;\n    public String message;\n    public Exception e;\n\n    public ErrorMsg(int code, String message){\n        this.code = code;\n        this.message = message;\n    }\n\n    public ErrorMsg(int code, String message, Exception e){\n        this.code = code;\n        this.message = message;\n        this.e = e;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/bean/Project.java",
    "content": "package com.bzai.gamesdk.build.bean;\n\nimport java.io.File;\n\n/**\n * Project 配置类\n */\npublic class Project {\n\n    /**\n     * 源码相对于项目所在路径。\n     */\n    public static final String JAVA_RELATIVE_PATH = \"src\" + File.separator\n            + \"main\" + File.separator + \"java\";\n\n    /**\n     * res资源文件相对于项目所在路径。\n     */\n    public static final String RES_RELATIVE_PATH = \"src\" + File.separator\n            + \"main\" + File.separator + \"res\";\n\n    /**\n     * assets文件相对于项目所在路径。\n     */\n    public static final String ASSETS_RELATIVE_PATH = \"src\" + File.separator\n            + \"main\" + File.separator + \"assets\";\n\n    /**\n     * libs相对于项目所在路径。\n     */\n    public static final String LIBS_RELATIVE_PATH = \"libs\";\n\n    /**\n     * Android manifest相对于项目所在路径。\n     */\n    public static final String ANDROID_MANIFEST_RELATIVE_PATH = \"src\" + File.separator\n            + \"main\" + File.separator + \"AndroidManifest.xml\";\n\n    /**\n     * jni libs相对于项目所在路径。\n     */\n    public static final String JNI_LIBS_RELATIVE_PATH = \"src\" + File.separator\n            + \"main\" + File.separator + \"jniLibs\";\n\n    /**\n     * jni libs相对于项目所在路径。\n     */\n    public static final String MAIN_FILE_RELATIVE_PATH = \"src\" + File.separator + \"main\";\n\n    /**\n     * unknown文件相对于项目所在路径。\n     */\n    public static final String UNKNOWN_FILE_RELATIVE_PATH = \"src\" + File.separator\n            + \"main\" + File.separator + \"unknown\";\n\n    /**\n     * project src file name.\n     */\n    public static final String SRC_FILE = \"src\";\n\n    /**\n     * project assets file name.\n     */\n    public static final String ASSETS_FILE = \"assets\";\n\n    /**\n     * project res file name.\n     */\n    public static final String RES_FILE = \"res\";\n\n    /**\n     * project libs file name.\n     */\n    public static final String LIBS_FILE = \"libs\";\n\n    /**\n     * project libs file name.\n     */\n    public static final String JNI_LIBS_FILE = \"jniLibs\";\n\n    /**\n     * project unknown file name.\n     */\n    public static final String UNKNOWN_FILE = \"unknown\";\n\n    /**\n     * app file name.\n     */\n    public static final String APP_FILE = \"app\";\n\n    /**\n     * project android manifest file name.\n     */\n    public static final String ANDROID_MANIFEST_FILE = \"AndroidManifest.xml\";\n\n    /**\n     * 项目名称\n     */\n    public String name;\n\n    /**\n     * 打包路径\n     */\n    public String path;\n\n    /**\n     * 服务器版本\n     */\n    public int version;\n\n    /**\n     * 服务器地址\n     */\n    public String url;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getPath() {\n        return path;\n    }\n\n    public void setPath(String path) {\n        this.path = path;\n    }\n\n    public int getVersion() {\n        return version;\n    }\n\n    public void setVersion(int version) {\n        this.version = version;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/tools/JavaTool.java",
    "content": "package com.bzai.gamesdk.build.tools;\n\nimport com.bzai.gamesdk.build.tools.exec.Shell;\nimport com.bzai.gamesdk.build.utils.Utils;\n\nimport javax.tools.JavaCompiler;\nimport javax.tools.StandardJavaFileManager;\nimport javax.tools.ToolProvider;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.nio.file.*;\nimport java.nio.file.attribute.BasicFileAttributes;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class JavaTool {\n\n\n    public static void compile(String sourceCodePath, String classPath, String classFileOutputPath,\n                               String logOutputPath) throws Exception{\n\n        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();\n\n        Path source = FileSystems.getDefault().getPath(sourceCodePath);\n        final List<String> javaFilePathList = new ArrayList<>();\n        Files.walkFileTree(source, new SimpleFileVisitor<Path>(){\n\n            @Override\n            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {\n                if (file.toString().endsWith(\".java\")){\n                    javaFilePathList.add(file.toAbsolutePath().toString());\n\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {\n                return FileVisitResult.CONTINUE;\n            }\n        });\n\n        //编译日志输出到文件\n        FileWriter fileWriter = null;\n        StandardJavaFileManager standardJavaFileManager = null;\n        boolean compileSucceed = true;\n        try {\n\n            if (!Utils.isEmpty(logOutputPath)){\n                fileWriter = new FileWriter(logOutputPath,true);\n            }\n\n            /**\n             * encoding    编译编码\n             * jars        需要加载的jar,-classpath选项就是定义class文件的查找目录\n             * sourceDir   java源文件存放目录\n             * Iterable<String> options = Arrays.asList(\"-encoding\", encoding, \"-classpath\", jars, \"-d\", targetDir, \"-sourcepath\", sourceDir);\n             */\n\n            List<String> optionList = new ArrayList<>();\n            optionList.addAll(Arrays.asList(\"-classpath\",classPath));\n            optionList.addAll(Arrays.asList(\"-d\",classFileOutputPath));\n            standardJavaFileManager = compiler.getStandardFileManager(null,null,null);\n            Iterable fileObjects = standardJavaFileManager.getJavaFileObjectsFromStrings(javaFilePathList);\n\n            JavaCompiler.CompilationTask compilationTask = compiler.getTask(fileWriter,null,null,optionList,null,fileObjects);\n            compileSucceed = compilationTask.call();\n\n        }catch (Exception e){\n            e.printStackTrace();\n\n        }finally {\n            if (null != fileWriter){\n                fileWriter.close();\n            }\n            if (null != standardJavaFileManager){\n                standardJavaFileManager.close();\n            }\n        }\n\n        if (!compileSucceed){//编译失败\n            throw new Exception(\"Compile .java to .class failed\");\n        }\n    }\n\n    /**\n     *\n     * 类文件打为jar包。\n     *\n     * @param classFilesPath\n     * @param jarOutputPath\n     */\n    public static void classFilesToJar(String classFilesPath, String jarOutputPath, String logOutputPath) throws Exception{\n\n        List<String> arguments = new ArrayList<String>();\n        arguments.add(\"jar\");\n        arguments.add(\"cvf\");\n        arguments.add(jarOutputPath);\n        arguments.add(\"-C\");\n        arguments.add(classFilesPath);\n        arguments.add(\".\");\n        Shell.execute(arguments, logOutputPath);\n    }\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/tools/ProGuardTool.java",
    "content": "package com.bzai.gamesdk.build.tools;\n\nimport com.bzai.gamesdk.build.tools.exec.Shell;\nimport proguard.Configuration;\nimport proguard.ConfigurationParser;\nimport proguard.ProGuard;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by bzai on 2018/04/20.\n */\npublic class ProGuardTool {\n\n    /**\n     * 混淆jar文件\n     *\n     * @param inputJar 需要混淆的jar。\n     * @param classPath 需要混淆的jar所引用的class path.\n     * @param proguardConfigFilePath 混淆配置文件路径。\n     * @param mappingFileOutputPath mapping 文件输出路径。\n     * @param outputJar 混淆之后的jar的输出路径。\n     */\n    public static void run(String inputJar, String classPath, String proguardConfigFilePath,\n                           String mappingFileOutputPath, String outputJar)  {\n        String[] commandLineArgs = new String[9];\n        commandLineArgs[0] = \"@\"+proguardConfigFilePath;\n        commandLineArgs[1] = \"-injars\";\n        commandLineArgs[2] = inputJar;\n        commandLineArgs[3] = \"-outjars\";\n        commandLineArgs[4] = outputJar;\n        commandLineArgs[5] = \"-printmapping\";\n        commandLineArgs[6] = mappingFileOutputPath;\n        commandLineArgs[7] = \"-libraryjars\";\n        commandLineArgs[8] = classPath;\n        Configuration var1 = new Configuration();\n        for (int i=0;i<commandLineArgs.length;i++){\n            System.out.printf(commandLineArgs[i]);\n        }\n\n        try {\n            ConfigurationParser var2 = new ConfigurationParser(commandLineArgs, System.getProperties());\n            try {\n                var2.parse(var1);\n            } finally {\n                var2.close();\n            }\n            (new ProGuard(var1)).execute();\n        } catch (Exception var7) {\n            if(var1.verbose) {\n                var7.printStackTrace();\n            } else {\n                System.err.println(\"Error: \" + var7.getMessage());\n            }\n        }\n    }\n\n    /**\n     * 混淆jar文件\n     *\n     * @param proguardToolPath 混淆工具的路径。\n     * @param inputJar 需要混淆的jar。\n     * @param classPath 需要混淆的jar所引用的class path.\n     * @param proguardConfigFilePath 混淆配置文件路径。\n     * @param mappingFileOutputPath mapping 文件输出路径。\n     * @param proguardLogOutputPath 混淆日志输出文件。\n     * @param outputJar 混淆之后的jar的输出路径。\n     *\n     * @throws Exception\n     */\n    public static void run(String proguardToolPath, String inputJar, String classPath, String proguardConfigFilePath,\n                           String mappingFileOutputPath, String proguardLogOutputPath, String outputJar) throws Exception {\n        List<String> commandLineArgs = new ArrayList<String>();\n        commandLineArgs.add(\"java\");\n        commandLineArgs.add(\"-jar\");\n        commandLineArgs.add(proguardToolPath);\n        commandLineArgs.add(\"-injars\");\n        commandLineArgs.add(inputJar);\n        commandLineArgs.add(\"-outjars\");\n        commandLineArgs.add(outputJar);\n        commandLineArgs.add(\"-printmapping\");\n        commandLineArgs.add(mappingFileOutputPath);\n        commandLineArgs.add(\"@\"+proguardConfigFilePath);\n        commandLineArgs.add(\"-libraryjars\");\n        commandLineArgs.add(classPath);\n        Shell.execute(commandLineArgs, proguardLogOutputPath);\n    }\n\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/tools/ServerTool.java",
    "content": "package com.bzai.gamesdk.build.tools;\n\nimport com.bzai.gamesdk.build.bean.Project;\nimport com.bzai.gamesdk.build.utils.FileUtils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Files;\nimport java.nio.file.LinkOption;\nimport java.nio.file.Path;\nimport java.util.Iterator;\nimport java.util.List;\n\n/**\n * 模拟服务器同步过程\n * 一般项目代码都是放到svn或者git上托管的,模拟服务器存储地址\n */\npublic class ServerTool {\n\n    public static void DownServerResource(List<Project> projectList, String checkoutDir) throws IOException{\n\n        String root_path = System.getProperty(\"user.dir\");\n        Iterator<Project> iterator = projectList.iterator();\n        while (iterator.hasNext()){\n            Project project = iterator.next();\n\n            // 获取源码目录\n            String projectName = project.getName();\n            String projectUrl = project.getUrl();\n            String projectResource = root_path + File.separator + projectUrl;\n//            System.out.println(projectResource);\n\n            // 工作目录\n            String destPath = checkoutDir + File.separator + projectName ;\n            Path destDirPath = FileSystems.getDefault().getPath(destPath);\n//            System.out.println(destDirPath);\n\n            boolean destDirPathExists = Files.exists(destDirPath, new LinkOption[]{LinkOption.NOFOLLOW_LINKS});\n            if (destDirPathExists){\n                FileUtils.delete(destPath);\n            }\n\n            FileUtils.copy(projectResource,destPath,false);\n\n            //设置本地存放路径\n            project.setPath(destPath);\n        }\n\n    }\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/tools/exec/Shell.java",
    "content": "package com.bzai.gamesdk.build.tools.exec;\n\nimport com.bzai.gamesdk.build.utils.Utils;\n\nimport java.io.*;\nimport java.util.List;\n\npublic class Shell {\n\n    public static void execute(List<String> commandSet, String logOutput) throws Exception{\n\n        Process ps = null;\n        int exitValue = -99;\n        ProcessBuilder builder = new ProcessBuilder(commandSet);\n        ps = builder.start();\n\n        OutputStreamWriter outputStreamWriter = null;\n        if (!Utils.isEmpty(logOutput)) {\n            outputStreamWriter = new OutputStreamWriter(new FileOutputStream(logOutput, true));\n            StreamForwarder errorStream = new StreamForwarder(ps.getErrorStream(), outputStreamWriter, 1, \"ERROR\");\n            StreamForwarder outputStream = new StreamForwarder(ps.getInputStream(), outputStreamWriter, 1, \"OUTPUT\");\n            errorStream.start();\n            outputStream.start();\n        }else{\n            outputStreamWriter = new OutputStreamWriter(System.out);\n            StreamForwarder errorStream = new StreamForwarder(ps.getErrorStream(), outputStreamWriter, 2, \"ERROR\");\n            StreamForwarder outputStream = new StreamForwarder(ps.getInputStream(), outputStreamWriter, 2, \"OUTPUT\");\n            errorStream.start();\n            outputStream.start();\n        }\n\n        exitValue = ps.waitFor();\n        ps.destroy();\n        if (exitValue != 0){\n            String inputCommandLine = \"\";\n            for (String option:commandSet){\n                if (!Utils.isEmpty(inputCommandLine)){\n                    inputCommandLine = inputCommandLine + \" \";\n                }\n                inputCommandLine = inputCommandLine + option;\n            }\n            throw new Exception(\"Could not exec command line [\"+inputCommandLine+\"]\");\n        }\n    }\n\n\n    static class StreamForwarder extends Thread{\n\n        private final InputStream mIn;\n        private final String mType;\n        private int mStreamType;\n        private final OutputStreamWriter mOs;\n\n        StreamForwarder(InputStream is, OutputStreamWriter os, int streamType, String type) {\n            mIn = is;\n            mType = type;\n            mOs = os;\n            mStreamType = streamType;\n        }\n\n        @Override\n        public void run() {\n            BufferedWriter bw = null;\n            BufferedReader br = null;\n\n            try {\n                bw = new BufferedWriter(mOs);\n                br = new BufferedReader(new InputStreamReader(mIn));\n                String line;\n                while ((line = br.readLine()) != null) {\n                    if (mType.equals(\"OUTPUT\")) {\n                        bw.write(line+\"\\n\");\n                    } else {\n                        bw.write(line+\"\\n\");\n                    }\n                }\n            } catch (IOException ex) {\n                ex.printStackTrace();\n            }finally {\n                try{\n                    //使用的是文件流,需要将流关闭。\n                    if (1 == mStreamType){\n                        if (br != null) {\n                            br.close();\n                        }\n                        if (null != bw){\n                            bw.close();\n                        }\n                    }\n                }catch (IOException e){\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/utils/FileUtils.java",
    "content": "package com.bzai.gamesdk.build.utils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.*;\nimport java.nio.file.attribute.BasicFileAttributes;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 操作文件类\n */\npublic class FileUtils {\n\n\n    private static final String TAG = \"FileUtils\";\n\n    public static void fileCopy(String srcPath, String destPath, boolean isReplaceExisting) throws IOException {\n        Path source = FileSystems.getDefault().getPath(srcPath);\n        Path destination = FileSystems.getDefault().getPath(destPath);\n        if (exists(destPath)){\n            if (isReplaceExisting){\n                Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING);\n            }\n        }else{\n            Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING);\n        }\n    }\n\n    /**\n     * smali file copy.\n     *\n     * @param sourcePath\n     * @param destPath\n     * @param filePathList\n     *      如果需要拷贝的文件和 filePathList 文件列表路径下的某个文件的有重复的话，\n     *      拷贝时直接拷贝覆盖 filePathList 文件列表路径下已经存在的文件。\n     * @throws IOException\n     */\n    public static void smaliFileCopy(final String appFirstSmaliPath, final String sourcePath, final String destPath,\n                                     final List<String> filePathList, final List<String> putToMainDexClassList) throws IOException {\n        final Path source = FileSystems.getDefault().getPath(sourcePath);\n        final Path destination = FileSystems.getDefault().getPath(destPath);\n        Files.walkFileTree(source, new SimpleFileVisitor<Path>(){\n\n            @Override\n            public FileVisitResult preVisitDirectory(Path preVisitDirectoryPath,\n                                                     BasicFileAttributes attrs) throws IOException {\n                Path relativePath = source.relativize(preVisitDirectoryPath);\n                String destPathStr = destination +File.separator +relativePath;\n                Path destPath = FileSystems.getDefault().getPath(destPathStr);\n                boolean pathExists =\n                        Files.exists(destPath,\n                                new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});\n                if (!pathExists){\n                    Files.createDirectory(destPath);\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFile(Path file,\n                                             BasicFileAttributes attrs) throws IOException {\n                Path relativePath = source.relativize(file);\n                String destPathStr = destination +File.separator +relativePath;\n                Path destPath = FileSystems.getDefault().getPath(destPathStr);\n\n                if (null != putToMainDexClassList && !putToMainDexClassList.isEmpty()){\n                    for (String classPath : putToMainDexClassList){\n                        String putMainDexSmaliPath = sourcePath + File.separator + classPath + \".smali\";\n                        String appPutMainDexSmaliPath = appFirstSmaliPath + File.separator + classPath + \".smali\";\n                        if(relativePath.toString().equals(classPath + \".smali\")){\n                            FileUtils.createFile(appPutMainDexSmaliPath, false);\n                            FileUtils.copy(putMainDexSmaliPath, appPutMainDexSmaliPath, true);\n                            return FileVisitResult.CONTINUE;\n                        }\n                    }\n                }\n\n                boolean isExists = false;\n                if (null != filePathList){\n                    for (String filePath : filePathList){\n                        String destFilePath = filePath.toString() +\n                                File.separator + relativePath.toString();\n                        if (FileUtils.exists(destFilePath)){\n                            isExists = true;\n                            Files.copy(file, FileSystems.getDefault().getPath(destFilePath),\n                                    StandardCopyOption.REPLACE_EXISTING);\n                            break;\n                        }\n                    }\n                }\n                if (!isExists){\n                    Files.copy(file, destPath, StandardCopyOption.REPLACE_EXISTING);\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFileFailed(Path file, IOException exc)\n                    throws IOException {\n                if (null != exc){\n                    exc.printStackTrace();\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult postVisitDirectory(Path dir,\n                                                      IOException exc) throws IOException {\n                return FileVisitResult.CONTINUE;\n            }\n\n        });\n    }\n\n    /**\n     * file copy\n     *\n     * @param srcPath\n     * @param destPath\n     * @param isReplaceExisting 如果文件存在是否替换\n     * @throws IOException\n     */\n    public static void copy(final String srcPath,final String destPath, final boolean isReplaceExisting) throws IOException {\n        final Path source = FileSystems.getDefault().getPath(srcPath);\n        final Path destination = FileSystems.getDefault().getPath(destPath);\n        Files.walkFileTree(source, new SimpleFileVisitor<Path>(){\n\n            @Override\n            public FileVisitResult preVisitDirectory(Path srcdir,\n                                                     BasicFileAttributes attrs) throws IOException {\n                Path relativizePath = source.relativize(srcdir);\n                String destPathStr = destination +File.separator +relativizePath;\n                Path destPath = FileSystems.getDefault().getPath(destPathStr);\n                boolean pathExists =\n                        Files.exists(destPath,\n                                new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});\n                if (!pathExists){\n                    Files.createDirectory(destPath);\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFile(Path file,\n                                             BasicFileAttributes attrs) throws IOException {\n                Path relativizePath = source.relativize(file);\n                String destPathStr = destination +File.separator +relativizePath;\n                Path destPath = FileSystems.getDefault().getPath(destPathStr);\n                boolean destPathExists = Files.exists(destPath, LinkOption.NOFOLLOW_LINKS);\n                if (destPathExists && !isReplaceExisting){\n                    return FileVisitResult.CONTINUE;\n                }\n                Files.copy(file, destPath, StandardCopyOption.REPLACE_EXISTING);\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFileFailed(Path file, IOException exc)\n                    throws IOException {\n                if (null != exc){\n                    exc.printStackTrace();\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult postVisitDirectory(Path dir,\n                                                      IOException exc) throws IOException {\n                return FileVisitResult.CONTINUE;\n            }\n\n        });\n    }\n\n    /**\n     * get special type file list\n     *\n     * @param srcPath path\n     * @param fileType file type\n     * @return file path list\n     * @throws IOException\n     */\n    public static List<String> getFileList(String srcPath, final String fileType) throws IOException {\n        final Path source = FileSystems.getDefault().getPath(srcPath);\n        final List<String> fileList = new ArrayList<String>();\n        Files.walkFileTree(source, new SimpleFileVisitor<Path>(){\n\n            @Override\n            public FileVisitResult preVisitDirectory(Path srcdir,\n                                                     BasicFileAttributes attrs) throws IOException {\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFile(Path file,\n                                             BasicFileAttributes attrs) throws IOException {\n                if (file.toFile().getName().endsWith(fileType)){\n                    fileList.add(file.toAbsolutePath().toString());\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFileFailed(Path file, IOException exc)\n                    throws IOException {\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult postVisitDirectory(Path dir,\n                                                      IOException exc) throws IOException {\n                return FileVisitResult.CONTINUE;\n            }\n\n        });\n        return fileList;\n    }\n\n    /**\n     * file copy\n     *\n     * @param srcPath source path\n     * @param destPath destination path\n     * @param copyFileType need to copy file type. example .txt or .png\n     * @param isReplaceExisting Whether replace if exist.\n     * @throws IOException\n     */\n    public static void copy(final String srcPath, final String destPath,\n                            final String copyFileType, final  boolean isReplaceExisting) throws IOException {\n        final Path source = FileSystems.getDefault().getPath(srcPath);\n        final Path destination = FileSystems.getDefault().getPath(destPath);\n        Files.walkFileTree(source, new SimpleFileVisitor<Path>(){\n\n            @Override\n            public FileVisitResult preVisitDirectory(Path srcdir,\n                                                     BasicFileAttributes attrs) throws IOException {\n                Path relativizePath = source.relativize(srcdir);\n                String destPathStr = destination +File.separator +relativizePath;\n                Path destPath = FileSystems.getDefault().getPath(destPathStr);\n                boolean pathExists =\n                        Files.exists(destPath,\n                                new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});\n                if (!pathExists){\n                    Files.copy(srcdir, destPath, StandardCopyOption.COPY_ATTRIBUTES);\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFile(Path file,\n                                             BasicFileAttributes attrs) throws IOException {\n                Path relativizePath = source.relativize(file);\n                String destPathStr = destination +File.separator +relativizePath;\n                Path destPath = FileSystems.getDefault().getPath(destPathStr);\n                boolean destPathExists = Files.exists(destPath, LinkOption.NOFOLLOW_LINKS);\n                if (destPathExists && !isReplaceExisting){\n                    return FileVisitResult.CONTINUE;\n                }\n                if (file.toFile().getName().endsWith(copyFileType)){\n                    Files.copy(file, destPath, StandardCopyOption.REPLACE_EXISTING);\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFileFailed(Path file, IOException exc)\n                    throws IOException {\n                if (null != exc){\n                    exc.printStackTrace();\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult postVisitDirectory(Path dir,\n                                                      IOException exc) throws IOException {\n                return FileVisitResult.CONTINUE;\n            }\n\n        });\n    }\n\n    /**\n     * file move\n     *\n     * @param srcPath\n     * @param destPath\n     * @throws IOException\n     */\n    public static void move(String srcPath, String destPath, final boolean isReplaceExisting) throws IOException {\n        final Path source = FileSystems.getDefault().getPath(srcPath);\n        final Path destination = FileSystems.getDefault().getPath(destPath);\n        Files.walkFileTree(source, new SimpleFileVisitor<Path>(){\n\n            @Override\n            public FileVisitResult preVisitDirectory(Path srcdir,\n                                                     BasicFileAttributes attrs) throws IOException {\n                Path relativizePath = source.relativize(srcdir);\n                String destPathStr = destination +File.separator +relativizePath;\n                Path destPath = FileSystems.getDefault().getPath(destPathStr);\n                boolean pathExists =\n                        Files.exists(destPath,\n                                new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});\n                if (!pathExists){\n                    Files.copy(srcdir, destPath, StandardCopyOption.COPY_ATTRIBUTES);\n                }else if(isReplaceExisting){\n                    Files.copy(srcdir, destPath, StandardCopyOption.REPLACE_EXISTING);\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFile(Path file,\n                                             BasicFileAttributes attrs) throws IOException {\n                Path relativizePath = source.relativize(file);\n                String destPathStr = destination +File.separator +relativizePath;\n                Path destPath = FileSystems.getDefault().getPath(destPathStr);\n                Files.move(file, destPath, StandardCopyOption.REPLACE_EXISTING);\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFileFailed(Path file, IOException exc)\n                    throws IOException {\n                if (null != exc){\n                    exc.printStackTrace();\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult postVisitDirectory(Path dir,\n                                                      IOException exc) throws IOException {\n                Files.deleteIfExists(dir);\n                return FileVisitResult.CONTINUE;\n            }\n\n        });\n    }\n\n    /**\n     * Copy\n     *\n     * @param srcPath\n     * @param destPath\n     * @param isRenameExisting\n     * @throws IOException\n     */\n    public static void copy(final String srcPath,final String destPath,\n                            final boolean isRenameExisting, final String prefix) throws IOException {\n        final Path source = FileSystems.getDefault().getPath(srcPath);\n        final Path destination = FileSystems.getDefault().getPath(destPath);\n        Files.walkFileTree(source, new SimpleFileVisitor<Path>(){\n\n            @Override\n            public FileVisitResult preVisitDirectory(Path srcdir,\n                                                     BasicFileAttributes attrs) throws IOException {\n                Path relativizePath = source.relativize(srcdir);\n                String destPathStr = destination +File.separator +relativizePath;\n                Path destPath = FileSystems.getDefault().getPath(destPathStr);\n                boolean pathExists =\n                        Files.exists(destPath,\n                                new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});\n                if (!pathExists){\n                    Files.createDirectory(destPath);\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFile(Path file,\n                                             BasicFileAttributes attrs) throws IOException {\n                Path relativizePath = source.relativize(file);\n                String destPathStr = destination +File.separator +relativizePath;\n                Path destPath = FileSystems.getDefault().getPath(destPathStr);\n                boolean destPathExists = Files.exists(destPath, LinkOption.NOFOLLOW_LINKS);\n                if (destPathExists && isRenameExisting){\n                    String fileName = destPath.toFile().getName();\n                    String destPathParentPathStr = destPath.toFile().getParentFile().getAbsolutePath();\n                    String newFileName = prefix + fileName;\n                    String newFilePathStr = destPathParentPathStr + File.separator + newFileName;\n                    while (FileUtils.exists(newFilePathStr)){\n                        newFileName = prefix + newFileName;\n                        newFilePathStr = destPathParentPathStr + File.separator + newFileName;\n                    }\n                    Files.copy(file, FileSystems.getDefault().getPath(newFilePathStr),\n                            StandardCopyOption.COPY_ATTRIBUTES);\n                }else{\n                    Files.copy(file, destPath, StandardCopyOption.REPLACE_EXISTING);\n                }\n\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFileFailed(Path file, IOException exc)\n                    throws IOException {\n                if (null != exc){\n                    exc.printStackTrace();\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult postVisitDirectory(Path dir,\n                                                      IOException exc) throws IOException {\n                return FileVisitResult.CONTINUE;\n            }\n\n        });\n    }\n\n    /**\n     * delete file.\n     * path can be directory or file\n     *\n     * @param path\n     * @throws IOException\n     */\n    public static void delete(String path) throws IOException {\n        Path source = FileSystems.getDefault().getPath(path);\n        Files.walkFileTree(source, new SimpleFileVisitor<Path>(){\n\n            @Override\n            public FileVisitResult preVisitDirectory(Path dir,\n                                                     BasicFileAttributes attrs)\n                    throws IOException {\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFile(Path file,\n                                             BasicFileAttributes attrs) throws IOException {\n                Files.delete(file);\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFileFailed(Path file, IOException exc)\n                    throws IOException {\n                if (null != exc){\n                    exc.printStackTrace();\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult postVisitDirectory(Path dir,\n                                                      IOException exc) throws IOException {\n                Files.delete(dir);\n                return FileVisitResult.CONTINUE;\n            }\n\n        });\n        Files.deleteIfExists(source);\n    }\n\n    /**\n     * delete child file.\n     *\n     * @param path\n     * @throws IOException\n     */\n    public static void deleteChildFile(String path) throws IOException {\n        File file = new File(path);\n        File[] files = file.listFiles();\n        for (File childFile : files){\n            if (childFile.isDirectory()){\n                delete(path);\n            }else{\n                Files.delete(FileSystems.getDefault().getPath(childFile.getAbsolutePath()));\n            }\n        }\n    }\n\n    /**\n     * delete file.\n     * path can be directory or file\n     *\n     * @param path\n     * @throws IOException\n     */\n    public static void deleteIfExists(String path) throws IOException {\n        Path source = FileSystems.getDefault().getPath(path);\n        boolean pathExists = Files.exists(source,\n                new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});\n        if (!pathExists){\n            return;\n        }\n        Files.walkFileTree(source, new SimpleFileVisitor<Path>(){\n\n            @Override\n            public FileVisitResult preVisitDirectory(Path dir,\n                                                     BasicFileAttributes attrs)\n                    throws IOException {\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFile(Path file,\n                                             BasicFileAttributes attrs) throws IOException {\n                Files.delete(file);\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult visitFileFailed(Path file, IOException exc)\n                    throws IOException {\n                if (null != exc){\n                    exc.printStackTrace();\n                }\n                return FileVisitResult.CONTINUE;\n            }\n\n            @Override\n            public FileVisitResult postVisitDirectory(Path dir,\n                                                      IOException exc) throws IOException {\n                Files.delete(dir);\n                return FileVisitResult.CONTINUE;\n            }\n        });\n\n        Files.deleteIfExists(source);\n    }\n\n    /**\n     * whether file exists\n     *\n     * @param path\n     * @return\n     */\n    public static boolean exists(String path){\n        Path destPath = FileSystems.getDefault().getPath(path);\n        return Files.exists(destPath,\n                new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});\n    }\n\n    /**\n     * Create Directories\n     *\n     * @param path\n     * @param isDeleteExists whether delete exits.\n     * @throws IOException\n     */\n    public static void createDirectories(String path, boolean isDeleteExists) throws IOException {\n        Path destPath = FileSystems.getDefault().getPath(path);\n        boolean pathExists =\n                Files.exists(destPath,\n                        new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});\n        if (pathExists){\n            if (isDeleteExists){\n                delete(path);\n            }else{\n                return;\n            }\n        }\n        Files.createDirectories(destPath);\n    }\n\n    public static List<String> getAllFilesRelativePath(String filePath){\n        final List<String> relativizePathList = new ArrayList<String>();\n        try {\n            final Path sourceFilePath = FileSystems.getDefault().getPath(filePath);\n            Files.walkFileTree(sourceFilePath, new SimpleFileVisitor<Path>(){\n\n                @Override\n                public FileVisitResult visitFile(Path file,\n                                                 BasicFileAttributes attrs) throws IOException {\n                    Path relativizePath = sourceFilePath.relativize(file);\n                    relativizePathList.add(relativizePath.toString());\n                    return FileVisitResult.CONTINUE;\n                }\n\n                @Override\n                public FileVisitResult visitFileFailed(Path file, IOException exc)\n                        throws IOException {\n                    return FileVisitResult.CONTINUE;\n                }\n\n            });\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n        return relativizePathList;\n    }\n\n    /**\n     * Create directory\n     *\n     * @param path path\n     * @param isDeleteExists whether to delete if file exists.\n     * @throws IOException\n     */\n    public static void createDirectory(String path, boolean isDeleteExists) throws IOException {\n        Path destPath = FileSystems.getDefault().getPath(path);\n        if (isDeleteExists){\n            boolean pathExists =\n                    Files.exists(destPath,\n                            new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});\n            if (pathExists){\n                delete(path);\n            }\n        }\n\n        Files.createDirectory(destPath);\n    }\n\n    /**\n     * Create directory\n     *\n     * @param path path\n     * @throws IOException\n     */\n    public static void createDirectory(String path) throws IOException {\n        Path destPath = FileSystems.getDefault().getPath(path);\n        Files.createDirectory(destPath);\n    }\n\n    /**\n     * Create directories\n     *\n     * @param path path\n     * @throws IOException\n     */\n    public static void createDirectories(String path) throws IOException {\n        Path destPath = FileSystems.getDefault().getPath(path);\n        Files.createDirectories(destPath);\n    }\n\n    /**\n     * create directory if non exists\n     *\n     * @param path\n     * @throws IOException\n     */\n    public static void createDirectoriesIfNonExists(String path) throws IOException {\n        Path destPath = FileSystems.getDefault().getPath(path);\n        boolean pathExists =\n                Files.exists(destPath,\n                        new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});\n        if (pathExists){\n            return;\n        }\n        Files.createDirectories(destPath);\n    }\n\n    /**\n     * create directory if non exists\n     *\n     * @param path\n     * @throws IOException\n     */\n    public static void createDirectoryIfNonExists(String path) throws IOException {\n        Path destPath = FileSystems.getDefault().getPath(path);\n        boolean pathExists =\n                Files.exists(destPath,\n                        new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});\n        if (pathExists){\n            return;\n        }\n        Files.createDirectory(destPath);\n    }\n\n    /**\n     * create file\n     *\n     * @param path file path\n     * @param isDeleteIfExists Whether to delete file if exists\n     * @throws IOException\n     */\n    public static void createFile(String path, boolean isDeleteIfExists) throws IOException {\n        Path filePath =\n                FileSystems.getDefault().getPath(path);\n        boolean filePathExists = Files.exists(filePath,\n                new LinkOption[]{LinkOption.NOFOLLOW_LINKS});\n        if (filePathExists){\n            if (isDeleteIfExists){\n                delete(path);\n            }else{\n                return;\n            }\n        }\n        File f = new File(path);\n        FileUtils.createDirectoriesIfNonExists(f.getParentFile().getAbsolutePath());\n        Files.createFile(filePath);\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/utils/Utils.java",
    "content": "package com.bzai.gamesdk.build.utils;\n\nimport java.io.File;\n\npublic class Utils {\n\n\n    public static final int OK = 0;\n\n    public static final int ERROR = 10001;\n\n    private static String OS = System.getProperty(\"os.name\").toLowerCase();\n\n\n    /**\n     * Linux 和 Windows分号分别使用的是\":\"和\";\"。\n     */\n    public static String OS_SEMICOLON = isWindows()?\";\":\":\";\n\n\n    public static boolean isWindows() {\n        return (OS.indexOf(\"win\") >= 0);\n    }\n\n    public static boolean isEmpty(String str){\n        if (null != str && !\"\".equals(str)){\n            return false;\n        }\n        return true;\n    }\n\n\n    /**\n     * Get jar file path list string, use the delimiter to splice.\n     *\n     * @param libsPath\n     * @return\n     */\n    public static String getJarPathSet(String libsPath, String delimiter){\n\n        File file = new File(libsPath);\n        String jarPathSet = \"\";\n        File[] files = file.listFiles();\n        for (int i = 0; i < files.length ; i++) {\n            File libFile = files[i];\n            if (libFile.getName().endsWith(\".jar\")){\n                if (!isEmpty(jarPathSet)){\n                    jarPathSet = jarPathSet + delimiter;\n                }\n                jarPathSet = jarPathSet + libFile.getAbsolutePath();\n            }\n        }\n\n        return jarPathSet;\n    }\n}\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/resources/config",
    "content": "\n\n/**\n* Android sdk 路径。\n* 是否必须：必须。\n*/\nandroidSdkPath=xxx\n\n\n/**\n* Android目标SDK版本。\n* 是否必须：必须。\n*/\ntargetSdkVersion=android-23\n\n\n/**\n*\n* 输出Jar的名称\n* 是否必须：必须\n*/\njarName=sdk_lexiang\n\n\n/**\n* 输出Jar的版本号\n* 是否必须：必须。\n*/\njarVersion=v1.0.0\n\n\n/**\n* 输出路径。\n* 是否必须：必须。\n*/\noutPutPath=D:\\\\BuildJar\n\n\n\n\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/resources/proguard_config.pro",
    "content": "\n-dontskipnonpubliclibraryclassmembers\n-dontshrink\n-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable\n-dontusemixedcaseclassnames\n-keepattributes SourceFile,LineNumberTable,*Annotation*,Signature,Deprecated,InnerClasses\n-keepparameternames\n-renamesourcefileattribute SourceFile\n-verbose\n\n-dontwarn android.support.v4.**\n\n# Keep names - Native method names. Keep all native class/method names.\n-keepclasseswithmembers,allowshrinking class * {\n    native <methods>;\n}\n\n# Also keep - Serialization code. Keep all fields and methods that are used for\n# serialization.\n-keepclassmembers class * extends java.io.Serializable {\n    static final long serialVersionUID;\n    static final java.io.ObjectStreamField[] serialPersistentFields;\n    private void writeObject(java.io.ObjectOutputStream);\n    private void readObject(java.io.ObjectInputStream);\n    java.lang.Object writeReplace();\n    java.lang.Object readResolve();\n}\n\n#保持 Parcelable 不被混淆\n-keep class * implements android.os.Parcelable {\n  public static final android.os.Parcelable$Creator *;\n}\n\n\n# 四大组件\n-keep class * extends android.app.Activity {\n    public protected <fields>;\n    <methods>;\n}\n-keep class * extends android.app.Application {\n    public protected <fields>;\n    <methods>;\n}\n-keep public class * extends android.app.Service\n-keep public class * extends android.content.BroadcastReceiver\n\n# 对外接口不参与混淆\n-keep class com.bzai.gamesdk.GameInfoSetting{ *; }\n-keep class com.bzai.gamesdk.api.** { *; }\n-keep class com.bzai.gamesdk.bean.** { *; }\n-keep class com.bzai.gamesdk.listener.** { *; }\n# SDK基础不混淆类\n-keep class com.bzai.gamesdk.common.utils_base.proguard.** { *; }\n-keep class * extends com.bzai.gamesdk.common.utils_base.proguard.** { *; }\n\n"
  },
  {
    "path": "GameSDKBuildJarTool/src/main/resources/project_list",
    "content": "\n###API接口层\nGameSDK_API=head,GameSDK_API\n\n###Project项目层\n#GameSDK_Project_Custom=head,GameSDK_BeginProject\\\\GameSDK_Project_Custom\nGameSDK_Project_JuHe=head,GameSDK_BeginProject\\\\GameSDK_Project_JuHe\n\n###Channel渠道层\n#GameSDK_Channel_Test=head,GameSDK_Channel\\\\GameSDK_Channel_Test\nGameSDK_Channel_Lexiang=head,GameSDK_Channel\\\\GameSDK_Channel_Lexiang\n\n###Manager逻辑控制层\nGameSDK_Module_Init=head,GameSDK_Manager\\\\GameSDK_Module_Init\nGameSDK_Module_Account=head,GameSDK_Manager\\\\GameSDK_Module_Account\nGameSDK_Module_Purchase=head,GameSDK_Manager\\\\GameSDK_Module_Purchase\n\n###Plugin功能插件层\nGameSDK_Manager_Impl=head,GameSDK_Manager_Impl\nGameSDK_Plugin_Alipay=head,GameSDK_Plugin\\\\GameSDK_Plugin_Alipay\nGameSDK_Plugin_Wechat=head,GameSDK_Plugin\\\\GameSDK_Plugin_Wechat\n\n###基础库\nGameSDK_Utils=head,GameSDK_Utils\n\n\n\n\n\n"
  },
  {
    "path": "GameSDKBuildJarTool/必读说明",
    "content": "\n### 该GameSDKBuildJarTool 用于自动化混淆SDK源码工具，只需要配置config、proguard_config_pro、project_list相关配置就可以了。\n\ncmd目录 为手动脚本运行Demo，配合博客来讲解自动化混淆的过程\n\n\n\n"
  },
  {
    "path": "GameSDKDemo_Release/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDKDemo_Release/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        applicationId \"com.bzai.gamesdkframe.demo\"\n        minSdkVersion 14\n        targetSdkVersion 26\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDKLibrary_Release')\n}\n"
  },
  {
    "path": "GameSDKDemo_Release/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDKDemo_Release/src/androidTest/java/com/bzai/gamesdkframe/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdkframe;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdkframe\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDKDemo_Release/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdkframe.demo\">\n\n    <application\n        android:name=\".GameApplication\"\n        android:icon=\"@drawable/ic_launcher\"\n        android:theme=\"@android:style/Theme.Light\"\n        android:label=\"@string/app_name\">\n        <activity android:name=\".GameSDKMain\"\n            android:configChanges=\"fontScale|orientation|keyboardHidden|locale|navigation|screenSize|uiMode\"\n            android:screenOrientation=\"sensorLandscape\">\n            <intent-filter>\n                <action android:name=\"Bzai.MAIN\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n\n        <activity android:name=\"com.bzai.gamesdk.common.utils_ui.activity.SplashActivity\"\n            android:screenOrientation=\"sensorLandscape\"\n            android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\"\n            android:configChanges=\"orientation|screenSize|keyboardHidden\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "GameSDKDemo_Release/src/main/java/com/bzai/gamesdkframe/demo/GameApplication.java",
    "content": "package com.bzai.gamesdkframe.demo;\n\nimport android.content.Context;\n\nimport com.bzai.gamesdk.SDKApplication;\n\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc: 游戏的Application 直接继承SDK的application\n */\n\npublic class GameApplication extends SDKApplication {\n\n    @Override\n    protected void attachBaseContext(Context base) {\n        super.attachBaseContext(base);\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n    }\n}\n"
  },
  {
    "path": "GameSDKDemo_Release/src/main/java/com/bzai/gamesdkframe/demo/GameSDKMain.java",
    "content": "package com.bzai.gamesdkframe.demo;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.widget.EditText;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.bzai.gamesdk.GameInfoSetting;\nimport com.bzai.gamesdk.api.SDKAPI;\nimport com.bzai.gamesdk.bean.params.PayParams;\nimport com.bzai.gamesdk.listener.AccountCallBackLister;\nimport com.bzai.gamesdk.listener.ExitCallBackLister;\nimport com.bzai.gamesdk.listener.InitCallBackLister;\nimport com.bzai.gamesdk.listener.PurchaseCallBackListener;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.regex.Pattern;\n\npublic class GameSDKMain extends Activity implements View.OnClickListener{\n\n    private String TAG = getClass().getName();\n    private EditText etPay,etReport;\n    private TextView tvLog;\n    private int pri = 0;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        initView();\n        init();\n    }\n\n\n    private void initView(){\n\n        findViewById(R.id.btn_login).setOnClickListener(this);\n        findViewById(R.id.btn_switchAccount).setOnClickListener(this);\n        findViewById(R.id.btn_logout).setOnClickListener(this);\n        findViewById(R.id.btn_pay).setOnClickListener(this);\n        findViewById(R.id.btn_exit).setOnClickListener(this);\n\n        etPay = (EditText) findViewById(R.id.et_inputPrice);\n        tvLog = (TextView) findViewById(R.id.tvLog);\n    }\n\n\n    @Override\n    public void onClick(View view) {\n        int id = view.getId();\n        switch (id) {\n            case R.id.btn_login:\n                login();\n                break;\n            case R.id.btn_switchAccount:\n                switchAccount();\n                break;\n            case R.id.btn_logout:\n                logout();\n                break;\n            case R.id.btn_pay:\n                purchase();\n                break;\n\n            case R.id.btn_exit:\n                exitGame();\n                break;\n            default:\n                break;\n        }\n    }\n\n\n    private AccountCallBackLister accountCallBackLister = new AccountCallBackLister() {\n\n        @Override\n        public void onAccountEventCallBack(String jsonStr) {\n            tvLog.setText(jsonStr);\n            showToast(jsonStr);\n\n            //CP解析数据格式\n            try {\n                JSONObject jsonObject = new JSONObject(jsonStr);\n                int code = jsonObject.getInt(\"eventType\");\n\n                if (code == AccountCallBackLister.LOGIN_SUCCESS ||\n                        code == AccountCallBackLister.SWITCH_ACCOUNT_SUCCESS){\n\n                }\n\n            } catch (JSONException e) {\n                e.printStackTrace();\n            }\n        }\n    };\n\n\n    private void init() {\n\n        //用于配置游戏的 gameid  和 gamekey\n        String gameid = \"1\";\n        String gamekey = \"222\";\n\n        GameInfoSetting gameInfoSetting = new GameInfoSetting(gameid,gamekey);\n        SDKAPI.getInstance().init(this, gameInfoSetting,accountCallBackLister, new InitCallBackLister() {\n\n            @Override\n            public void onSuccess() {\n                tvLog.setText(\"初始化状态：初始化成功\");\n                showToast(\"初始化状态：初始化成功\");\n            }\n\n            @Override\n            public void onFailure(int code, String msg) {\n                String message = \"初始化状态\"\n                        +\"\\n错误码:\\n\" + code\n                        +\"\\n错误信息:\\n\" + msg;\n                tvLog.setText(message);\n                showToast(message);\n            }\n        });\n    }\n\n\n    /**\n     * 账号登陆\n     */\n    private void login() {\n        SDKAPI.getInstance().login(this);\n    }\n\n    /**\n     * 切换账号\n     */\n    private void switchAccount(){\n        SDKAPI.getInstance().switchAccount(this);\n    }\n\n    /**\n     * 账号登出\n     */\n    private void logout() {\n        SDKAPI.getInstance().logout(this);\n    }\n\n    /**\n     * 购买\n     */\n    private void purchase() {\n\n        String pri_str = etPay.getText().toString();\n        if (!isDecimal(pri_str) && !isInteger(pri_str)) {\n            showToast(\"Please enter Correct values.\");\n            return;\n        }\n\n        try {\n            pri = Integer.valueOf(pri_str);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        /**\n         *  productId\t\t\t商品ID\n         *  productName\t\t\t商品名称\n         *  productDesc\t\t\t商品描述\n         *\n         *  money\t\t\t\t商品单价 (以分为单位)\n         *\n         *  roleID              当前游戏内角色ID\n         *  roleName            当前游戏内角色名称\n         *  roleLevel           玩家等级\n         *  serverID            当前玩家所在的服务器ID\n         *  serverName          当前玩家所在的服务器名称\n         *\n         *  notifyUrl           支付回调地址\n         *  extraInfo\t\t\t透传给 cp服务器的字段\n         *  gorder              CP订单号\n         */\n\n        //商品信息\n        PayParams payParams = new PayParams();\n        payParams.setProductName(\"金币\");\n        payParams.setProductDesc(\"一金币等于十银币\");\n        payParams.setProductId(\"9000\"); //SDK的商品ID\n\n        //金额信息\n        payParams.setMoney(pri);\n\n        //玩家信息\n        payParams.setRoleID(\"123456\");\n        payParams.setRoleName(\"小明\");\n        payParams.setRoleLevel(\"15\");\n        payParams.setServerID(\"11\");\n        payParams.setServerName(\"服务十一区\");\n\n        //支付配置信息\n        payParams.setNotifyUrl(\"www.baidu.com\");\n        payParams.setExtension(\"extra\");\n        payParams.setGorder(\"DD123456\");\n\n        SDKAPI.getInstance().pay(this, payParams,new PurchaseCallBackListener() {\n\n            //创建SDK订单成功就返回，方便CP查询该笔订单状态\n            @Override\n            public void onOrderId(String orderId) {\n                showToast(orderId);\n            }\n\n            @Override\n            public void onSuccess() {\n                String message = \"支付成功\";\n                tvLog.setText(message);\n                showToast(message);\n            }\n\n            @Override\n            public void onFailure(int code, String msg) {\n\n                String message = \"支付失败\\n:\\n错误:\\n\" + code;\n                tvLog.setText(message);\n                showToast(message);\n\n            }\n\n            @Override\n            public void onCancel() {\n                String message = \"支付取消\\n:\\n错误:\\n\" ;\n                tvLog.setText(message);\n                showToast(message);\n            }\n\n            //支付完成，没有正确支付回调时，会返回该结果\n            @Override\n            public void onComplete() {\n                String message = \"支付完成\\n\" ;\n                tvLog.setText(message);\n                showToast(message);\n            }\n\n        });\n    }\n\n\n\n    //--------------------------------------------------退出接口---------------------------------------------\n\n    private void exitGame(){\n\n        SDKAPI.getInstance().exit(GameSDKMain.this,new ExitCallBackLister(){\n\n            //存在退出框,并且点击退出成功\n            @Override\n            public void onExitDialogSuccess() {\n                Log.d(TAG,\"退出成功\");\n                SDKAPI.getInstance().onDestroy(GameSDKMain.this);\n                System.exit(0);\n            }\n\n            //存在退出框,并且点击取消退出\n            @Override\n            public void onExitDialogCancel() {\n                Log.d(TAG,\"退出取消\");\n            }\n\n            //不存在退出框，需要游戏自己实现退出框,然后调用SDK释放资源接口\n            @Override\n            public void onNotExitDialog() {\n\n                AlertDialog.Builder builder = new AlertDialog.Builder(GameSDKMain.this);\n                builder.setTitle(\"退出游戏\");\n                builder.setPositiveButton(\"退出\", new DialogInterface.OnClickListener() {\n\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n\n                        SDKAPI.getInstance().onDestroy(GameSDKMain.this);\n                        System.exit(0);\n                    }\n                });\n                builder.show();\n\n            }\n        });\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        switch (keyCode) {\n            case KeyEvent.KEYCODE_BACK:\n                exitGame();\n                break;\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public void onBackPressed() {\n        super.onBackPressed();\n        exitGame();\n    }\n\n    private void showToast(String msg) {\n        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();\n    }\n\n    // 浮点型判断 (Floating-point judgment)\n    public static boolean isDecimal(String str) {\n        if (str == null || \"\".equals(str))\n            return false;\n        java.util.regex.Pattern pattern = Pattern.compile(\"[0-9]*(\\\\.?)[0-9]*\");\n        return pattern.matcher(str).matches();\n    }\n\n    // 整型判断 (Integer to determine)\n    public static boolean isInteger(String str) {\n        if (str == null)\n            return false;\n        Pattern pattern = Pattern.compile(\"[0-9]+\");\n        return pattern.matcher(str).matches();\n    }\n\n    //--------------------------------------------------生命周期接口---------------------------------------------\n\n    @Override\n    protected void onStart() {\n        super.onStart();\n        SDKAPI.getInstance().onStart(GameSDKMain.this);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        SDKAPI.getInstance().onResume(GameSDKMain.this);\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        SDKAPI.getInstance().onPause(GameSDKMain.this);\n    }\n\n    @Override\n    protected void onStop() {\n        super.onStop();\n        SDKAPI.getInstance().onStop(GameSDKMain.this);\n    }\n\n    @Override\n    protected void onRestart() {\n        super.onRestart();\n        SDKAPI.getInstance().onRestart(GameSDKMain.this);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        SDKAPI.getInstance().onDestroy(GameSDKMain.this);\n    }\n\n    @Override\n    protected void onNewIntent(Intent intent) {\n        super.onNewIntent(intent);\n        SDKAPI.getInstance().onNewIntent(GameSDKMain.this,intent);\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        SDKAPI.getInstance().onActivityResult(GameSDKMain.this,requestCode,resultCode,data);\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        SDKAPI.getInstance().onRequestPermissionsResult(GameSDKMain.this,requestCode, permissions, grantResults);\n    }\n}\n"
  },
  {
    "path": "GameSDKDemo_Release/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/white\"\n    android:paddingTop=\"10dp\"\n    android:paddingLeft=\"10dp\"\n    android:paddingRight=\"10dp\"\n    android:paddingBottom=\"10dp\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:orientation=\"horizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <Button\n                android:id=\"@+id/btn_login\"\n                android:layout_width=\"200dp\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"登录\" />\n\n            <Button\n                android:id=\"@+id/btn_switchAccount\"\n                android:layout_width=\"200dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"3dp\"\n                android:text=\"切换账号\" />\n\n            <Button\n                android:id=\"@+id/btn_logout\"\n                android:layout_width=\"200dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"3dp\"\n                android:text=\"注销\" />\n\n            <EditText\n                android:id=\"@+id/et_inputPrice\"\n                android:layout_width=\"200dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"3dp\"\n                android:background=\"@android:drawable/edit_text\"\n                android:text=\"1\"\n                android:textColor=\"@color/colorPrimaryDark\" />\n\n            <Button\n                android:id=\"@+id/btn_pay\"\n                android:layout_width=\"200dp\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"支付\" />\n\n            <Button\n                android:id=\"@+id/btn_exit\"\n                android:layout_width=\"200dp\"\n                android:layout_marginTop=\"3dp\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"退出\" />\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\">\n            <View\n                android:layout_width=\"10dp\"\n                android:layout_height=\"match_parent\"/>\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n            <TextView\n                android:layout_marginTop=\"10dp\"\n                android:id=\"@+id/tvLog\"\n                android:hint=\"显示回调信息：\"\n                android:layout_width=\"match_parent\"\n                android:textColor=\"@color/black\"\n                android:layout_height=\"wrap_content\" />\n        </LinearLayout>\n\n    </LinearLayout>\n\n</ScrollView>\n"
  },
  {
    "path": "GameSDKDemo_Release/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n    <color name=\"white\">#FFFFFF</color>\n    <color name=\"black\">#000000</color>\n</resources>\n"
  },
  {
    "path": "GameSDKDemo_Release/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">GameSDKFrameDemo</string>\n</resources>\n"
  },
  {
    "path": "GameSDKDemo_Release/src/test/java/com/bzai/gamesdkframe/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdkframe;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDKLibrary_Release/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDKLibrary_Release/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 27\n    buildToolsVersion '27.0.3'\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 27\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n}\n"
  },
  {
    "path": "GameSDKLibrary_Release/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDKLibrary_Release/src/androidTest/java/com/suyutech/baselibrary/ExampleInstrumentedTest.java",
    "content": "package com.suyutech.baselibrary;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.suyutech.baselibrary.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDKLibrary_Release/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.library\" >\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n\n</manifest>\n\n"
  },
  {
    "path": "GameSDKLibrary_Release/src/main/assets/Channel_config.txt",
    "content": "{\n    \"channel\": [\n        {\n            \"channel_name\": \"channel\",\n            \"class_name\": \"com.bzai.gamesdk.channel.test.TestChannelSDK\",\n            \"description\": \"测试渠道SDK\",\n            \"version\": \"1.0.0\"\n        }\n    ]\n}"
  },
  {
    "path": "GameSDKLibrary_Release/src/main/assets/Plugin_config.txt",
    "content": "{\n    \"plugin\": [\n        {\n            \"plugin_name\": \"plugin_wechat\",\n            \"class_name\": \"com.bzai.gamesdk.plugin.wechat.WechatPlugin\",\n            \"description\": \"微信功能插件\",\n            \"version\": \"5.1.4\"\n        },\n        {\n            \"plugin_name\": \"plugin_alipay\",\n            \"class_name\": \"com.bzai.gamesdk.plugin.alipay.AlipayPlugin\",\n            \"description\": \"支付宝功能插件\",\n            \"version\": \"15.5.5\"\n        }\n    ]\n}"
  },
  {
    "path": "GameSDKLibrary_Release/src/main/assets/Project_config.txt",
    "content": "{\n    \"project\": [\n        {\n            \"project_name\": \"project\",\n            \"class_name\": \"com.bzai.gamesdk.project.JuHeProject\",\n            \"description\": \"聚合SDK项目\",\n            \"version\": \"1.0.0\"\n        }\n    ]\n}"
  },
  {
    "path": "GameSDKLibrary_Release/src/main/assets/SDKInfo.json",
    "content": "{\n  \"sdk_type\": \"1\",\n  \"sdk_name\": \"SDK_JuHe\",\n  \"sdk_version\": \"1.0.0\",\n  \"sdk_url\": \"http://www.baidu.com/\"\n}"
  },
  {
    "path": "GameSDKLibrary_Release/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">GameSDK_Plugin_Alipay</string>\n</resources>\n"
  },
  {
    "path": "GameSDKLibrary_Release/src/test/java/com/suyutech/baselibrary/ExampleUnitTest.java",
    "content": "package com.suyutech.baselibrary;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDK_API/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDK_API/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDK_Project_JuHe')\n//    compile project(':GameSDK_Project_Custom')\n}\n"
  },
  {
    "path": "GameSDK_API/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDK_API/src/androidTest/java/com/bzai/gamesdk/api/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdk.api;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdk.api.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDK_API/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.api\" />\n"
  },
  {
    "path": "GameSDK_API/src/main/java/com/bzai/gamesdk/GameInfoSetting.java",
    "content": "package com.bzai.gamesdk;\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc:\n *\n *    用于对外给CP获取对应的游戏 gameid 和 gamekey\n */\n\npublic class GameInfoSetting {\n\n    public String gameid;\n    public String gamekey;\n\n    public GameInfoSetting(String gameid, String gamekey){\n\n        this.gameid = gameid;\n        this.gamekey = gamekey;\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_API/src/main/java/com/bzai/gamesdk/SDKApplication.java",
    "content": "package com.bzai.gamesdk;\nimport android.content.Context;\n\nimport com.bzai.gamesdk.project.ProjectApplication;\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc: 项目SDK的application\n */\n\npublic class SDKApplication extends ProjectApplication {\n\n    @Override\n    protected void attachBaseContext(Context context) {\n        super.attachBaseContext(context);\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_API/src/main/java/com/bzai/gamesdk/api/SDKAPI.java",
    "content": "package com.bzai.gamesdk.api;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.widget.Toast;\n\nimport com.bzai.gamesdk.GameInfoSetting;\nimport com.bzai.gamesdk.bean.info.AccountEventResultInfo;\nimport com.bzai.gamesdk.bean.info.PlayerInfo;\nimport com.bzai.gamesdk.bean.params.GameRoleParams;\nimport com.bzai.gamesdk.bean.params.PayParams;\nimport com.bzai.gamesdk.common.utils_base.config.ErrCode;\nimport com.bzai.gamesdk.common.utils_base.config.TypeConfig;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonObject;\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.parse.project.Project;\nimport com.bzai.gamesdk.common.utils_base.parse.project.ProjectManager;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\nimport com.bzai.gamesdk.common.utils_base.utils.ObjectUtils;\nimport com.bzai.gamesdk.listener.AccountCallBackLister;\nimport com.bzai.gamesdk.listener.ExitCallBackLister;\nimport com.bzai.gamesdk.listener.InitCallBackLister;\nimport com.bzai.gamesdk.listener.PurchaseCallBackListener;\nimport com.bzai.gamesdk.module.account.bean.AccountBean;\nimport com.bzai.gamesdk.module.account.bean.AccountCallBackBean;\nimport com.bzai.gamesdk.module.purchase.PurchaseResult;\n\nimport java.util.HashMap;\n\n/**\n * Created by bzai on 2018/7/19.\n * <p>\n * Desc:\n */\npublic class SDKAPI {\n\n    private final String TAG = getClass().getSimpleName();\n\n    private volatile static SDKAPI INSTANCE;\n\n    private SDKAPI() {\n    }\n\n    public static SDKAPI getInstance() {\n        if (INSTANCE == null) {\n            synchronized (SDKAPI.class) {\n                if (INSTANCE == null) {\n                    INSTANCE = new SDKAPI();\n                }\n            }\n        }\n        return INSTANCE;\n    }\n\n//    private Project project = ProjectManager.getInstance().getProject(\"custom_project\"); //获取实际的项目对象\n//    private Project project = ProjectManager.getInstance().getProject(\"juhe_project\"); //获取实际的项目对象\n    private Project project = ProjectManager.getInstance().getProject(\"project\"); //获取实际的项目对象\n\n    /**-----------------------------------生命周期接口--------------------------------------**/\n\n    public void onCreate(Activity activity, Bundle savedInstanceState) {\n        project.onCreate(activity,savedInstanceState);\n    }\n\n    public void onStart(Activity activity) {\n        project.onStart(activity);\n    }\n\n    public void onResume(Activity activity) {\n        project.onResume(activity);\n    }\n\n    public void onPause(Activity activity) {\n        project.onPause(activity);\n    }\n\n    public void onStop(Activity activity) {\n        project.onStop(activity);\n    }\n\n    public void onRestart(Activity activity) {\n        project.onRestart(activity);\n    }\n\n    public void onDestroy(Activity activity) {\n        project.onDestroy(activity);\n    }\n\n    public void onNewIntent(Activity activity,Intent intent){\n        project.onNewIntent(activity,intent);\n    }\n\n    public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {\n        project.onActivityResult(activity,requestCode,resultCode,data);\n    }\n\n    public void onRequestPermissionsResult(Activity activity,int requestCode, String[] permissions,int[] grantResults) {\n        project.onRequestPermissionsResult(activity,requestCode,permissions,grantResults);\n    }\n\n\n    /**-----------------------------------SDK接口--------------------------------------**/\n\n\n    /**\n     * 初始化接口\n     * @param activity 游戏activity\n     * @param gameInfoSetting 游戏参数对象\n     * @param accountCallBackLister 账号回调监听\n     * @param initCallBackListener 初始化回调监听\n     */\n    public void init(final Activity activity, GameInfoSetting gameInfoSetting, AccountCallBackLister accountCallBackLister,\n                     final InitCallBackLister initCallBackListener){\n\n        //检测是否已设置配置游戏必须参数\n        if (TextUtils.isEmpty(gameInfoSetting.gameid) || TextUtils.isEmpty(gameInfoSetting.gamekey)){\n            Toast.makeText(activity,\"param one of GameInfoSetting is null, please checks first\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        //检测是否已设置登录监听\n        if (accountCallBackLister == null){\n            Toast.makeText(activity,\"AccountCallBackLister is null, please setAccountCallBackLister first\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        //设置账号监听回调\n        mAccountCallCallBackLister = accountCallBackLister;\n        project.setAccountCallBackLister(SDKAccountCallBackLister);\n\n        project.init(activity, gameInfoSetting.gameid, gameInfoSetting.gamekey, new CallBackListener() {\n\n            @Override\n            public void onSuccess(Object o) {\n                initCallBackListener.onSuccess();\n            }\n\n            @Override\n            public void onFailure(int code, String msg) {\n                initCallBackListener.onFailure(code,msg);\n            }\n        });\n    }\n\n\n\n    /***********************************************************************************************\n     *\n     *\n     *  设置Account回调接口,避免渠道有些渠道登录是从浮窗或个人中心等入口接口回调回来，没法正确回调给CP\n     *\n     *\n     **********************************************************************************************/\n    private AccountCallBackLister mAccountCallCallBackLister;\n\n    private void accountCallBack(int type, int statusCode, String msg, AccountBean loginInfo){\n\n        AccountEventResultInfo accountResult = new AccountEventResultInfo();\n        accountResult.setEventType(type);\n        accountResult.setStatusCode(statusCode);\n        accountResult.setMsg(msg);\n        if (loginInfo != null){\n\n            PlayerInfo playerInfo = new PlayerInfo();\n            playerInfo.setPlayerId(loginInfo.getUserID());\n            playerInfo.setToken(loginInfo.getUserToken());\n            accountResult.setPlayerInfo(playerInfo);\n\n        }else {\n            accountResult.setPlayerInfo(new PlayerInfo());\n        }\n\n        Gson gson = new Gson();\n        String jsonStr = gson.toJson(accountResult);\n        if (mAccountCallCallBackLister != null){\n            mAccountCallCallBackLister.onAccountEventCallBack(jsonStr);\n        }\n    }\n\n    private void loginEventCallBack(int code, AccountBean loginInfo, String msg){\n\n        if (code == ErrCode.SUCCESS){\n            accountCallBack(AccountCallBackLister.LOGIN_SUCCESS, ErrCode.SUCCESS ,msg, loginInfo);\n\n        }else if (code == ErrCode.CANCEL){\n            accountCallBack(AccountCallBackLister.LOGIN_CANCEL, code, msg, null);\n\n        }else if (code == ErrCode.CHANNEL_LOGIN_CLOSE){\n            accountCallBack(AccountCallBackLister.LOGIN_FAILURE, code, msg, null);\n\n        } else {\n            accountCallBack(AccountCallBackLister.LOGIN_FAILURE, code, msg, null);\n        }\n    }\n\n    private void switchEventCallBack(int code, AccountBean loginInfo, String msg){\n\n        if (code == ErrCode.SUCCESS){\n            accountCallBack(AccountCallBackLister.SWITCH_ACCOUNT_SUCCESS, ErrCode.SUCCESS, msg,loginInfo);\n\n        }else if (code == ErrCode.CANCEL){\n            accountCallBack(AccountCallBackLister.SWITCH_ACCOUNT_CANCEL, code, msg, null);\n\n        } else {\n            accountCallBack(AccountCallBackLister.SWITCH_ACCOUNT_FAILURE,code, msg, null);\n        }\n    }\n\n    private void logoutEventCallBack(int code, String msg){\n\n        if (code == ErrCode.SUCCESS){\n            accountCallBack(AccountCallBackLister.LOGOUT_SUCCESS, ErrCode.SUCCESS, msg, null);\n\n        }else if (code == ErrCode.CANCEL){\n            accountCallBack(AccountCallBackLister.LOGOUT_CANCEL, code, msg, null);\n\n        } else {\n            accountCallBack(AccountCallBackLister.LOGOUT_FAILURE, code, msg , null);\n        }\n    }\n\n    /**\n     * 将Project层的结果回调到这里\n     */\n    private CallBackListener SDKAccountCallBackLister = new CallBackListener<AccountCallBackBean>() {\n\n        /**\n         * 事件结果都回调到这里来,包括失败，取消的\n         */\n        @Override\n        public void onSuccess(AccountCallBackBean callBackBean) {\n\n            int event = callBackBean.getEvent();\n            int code = callBackBean.getErrorCode();\n            AccountBean loginInfo = callBackBean.getAccountBean();\n            String msg = callBackBean.getMsg();\n            switch (event){\n                case TypeConfig.LOGIN:\n                    loginEventCallBack(code,loginInfo,msg);\n                    break;\n\n                case TypeConfig.SWITCHACCOUNT:\n                    switchEventCallBack(code,loginInfo,msg);\n                    break;\n\n                case TypeConfig.LOGOUT:\n                    logoutEventCallBack(code,msg);\n                    break;\n                default:\n                    break;\n            }\n        }\n\n        @Override\n        public void onFailure(int code, String msg) {\n            //不会走到这里来\n        }\n    };\n\n\n    /**\n     * 账号登录\n     * @param activity 游戏activity\n     */\n    public void login(Activity activity){\n        project.login(activity, null);\n    }\n\n\n    /**\n     * 切换账号\n     * @param activity 游戏activity\n     */\n    public void switchAccount(Activity activity){\n        project.switchAccount(activity);\n    }\n\n    /**\n     * 账号注销\n     * @param activity 游戏activity\n     */\n    public void logout(Activity activity){\n        project.logout(activity);\n    }\n\n    /**\n     * 购买\n     * @param activity 游戏activity\n     * @param params 购买参数\n     * @param purchaseCallBackListener 购买回调\n     */\n    public void pay(Activity activity, PayParams params, final PurchaseCallBackListener purchaseCallBackListener){\n\n        //将实体对象装换为Map集合，方便后续自动扩展\n        HashMap<String,Object> payParams = ObjectUtils.objectToMap(params);\n        project.pay(activity, payParams, new CallBackListener<PurchaseResult>() {\n\n            @Override\n            public void onSuccess(PurchaseResult purchaseResult) {\n\n                int type = purchaseResult.status;\n                if (type == PurchaseResult.OrderState){ //创建订单成功回调\n\n                    JsonObject object = (JsonObject) purchaseResult.message;\n                    String orderID = object.get(\"orderId\").getAsString();\n                    purchaseCallBackListener.onOrderId(orderID);\n                }\n\n                if(type == PurchaseResult.PurchaseState){//支付成功回调\n                    purchaseCallBackListener.onSuccess();\n                }\n\n            }\n\n            @Override\n            public void onFailure(int code, String msg) {\n\n                if (purchaseCallBackListener != null){\n                    if (code == ErrCode.CANCEL){\n                        purchaseCallBackListener.onCancel();\n\n                    }else if (code == ErrCode.NO_PAY_RESULT){\n\n                        purchaseCallBackListener.onComplete();\n\n                    }else {\n\n                        purchaseCallBackListener.onFailure(code,msg);\n                    }\n                }\n            }\n        });\n\n    }\n\n    /**\n     * 退出接口\n     * @param activity 游戏activity\n     * @param exitCallBackLister 退出回调\n     */\n    public void exit(Activity activity, final ExitCallBackLister exitCallBackLister){\n\n        project.exit(activity, new CallBackListener() {\n\n            @Override\n            public void onSuccess(Object object) {\n\n                //存在渠道退出框,并且点击退出成功\n                exitCallBackLister.onExitDialogSuccess();\n            }\n\n            @Override\n            public void onFailure(int code, String msg) {\n\n                if (code == ErrCode.CANCEL){\n                    exitCallBackLister.onExitDialogCancel();\n\n                }else if (code == ErrCode.NO_EXIT_DIALOG){\n                    exitCallBackLister.onNotExitDialog();//不存在渠道退出框\n\n                } else{ //其他错误的时候,默认是没有回调框的\n\n                    exitCallBackLister.onNotExitDialog();//不存在渠道退出框\n                }\n\n            }\n        });\n\n    }\n\n    /**\n     * 显示浮窗\n     * @param activity\n     */\n    public void showFloatWindow(Activity activity){\n        project.showFloatView(activity);\n    }\n\n    /**\n     * 隐藏浮窗\n     */\n    public void dismissFloatView(Activity activity){\n        project.dismissFloatView(activity);\n    }\n\n\n    /**\n     * 上报数据信息\n     * @param activity 游戏activity\n     * @param gameRoleParams 游戏参数实体\n     */\n    public void submitRoleInfo(Activity activity, GameRoleParams gameRoleParams){\n\n        //将实体对象装换为Map集合，方便后续自动扩展\n        HashMap<String,Object> reportData = ObjectUtils.objectToMap(gameRoleParams);\n        LogUtils.d(TAG,reportData.toString());\n        project.reportData(activity,reportData);\n    }\n\n    public String getChannelId(){\n        return project.getChannelID();\n    }\n}\n"
  },
  {
    "path": "GameSDK_API/src/main/java/com/bzai/gamesdk/bean/info/AccountEventResultInfo.java",
    "content": "package com.bzai.gamesdk.bean.info;\n\n/**\n * Created by bzai on 2018/4/17.\n * <p>\n * Desc:\n *\n *  用于装换成Json对象的实体类,不对外提供get方法\n *\n */\n\npublic class AccountEventResultInfo {\n\n\n    private int eventType; //事件类型\n\n    private int statusCode; //事件ID的状态码\n\n    private String message; //描述信息\n\n    private PlayerInfo playerInfo; //用户信息\n\n    public void setEventType(int eventType) {\n        this.eventType = eventType;\n    }\n\n    public void setStatusCode(int statusCode) {\n        this.statusCode = statusCode;\n    }\n\n    public void setMsg(String message) {\n        this.message = message;\n    }\n\n    public void setPlayerInfo(PlayerInfo playerInfo) {\n        this.playerInfo = playerInfo;\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_API/src/main/java/com/bzai/gamesdk/bean/info/PlayerInfo.java",
    "content": "package com.bzai.gamesdk.bean.info;\n\n/**\n * Created by bzai on 2018/4/11.\n * <p>\n * Desc:  返回外界的用户信息实体类\n */\n\npublic class PlayerInfo {\n\n    private String playerId;\n    private String token;\n\n    public String getPlayerId() {\n        return playerId;\n    }\n\n    public void setPlayerId(String playerId) {\n        this.playerId = playerId;\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    public void setToken(String token) {\n        this.token = token;\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_API/src/main/java/com/bzai/gamesdk/bean/params/GameRoleParams.java",
    "content": "package com.bzai.gamesdk.bean.params;\n\n/**\n * Created by bzai on 2018/4/18.\n * <p>\n * Desc:\n *\n *  数据上报透传实体类,只提供set方法，不对外提供get方法\n *\n *  ReportId            数据上传类型：\n *\n *      1:进入游戏\n *      2:登录游戏\n *      3:选择区服\n *      4:角色创建\n *      5:角色升级\n *      6:角色支付\n *      7:退出游戏\n *\n *  roleId\t\t\t    角色ID\n *  roleName\t\t\t角色名称\n *  roleLevel\t\t\t角色等级\n *  roleCreateTime      角色创建时间 （选填）\n *  roleVipLevel        角色vip等级 （选填）\n *  roleUpLevelTime     角色升级时间 （选填）\n *  roleUnionName       角色所在家族/工会名称 (选填)\n *  roleBalance         角色充值余额(选填)\n *\n *  serverId\t\t    登录所属的游戏服务器唯一标识\n *  serverName\t\t\t登录所属的游戏服务器名称\n *\n *  extraInfo           拓展字段信息\n *\n */\n\npublic class GameRoleParams {\n\n    //时间类型，可扩展\n    private int ReportId;\n\n    //角色信息\n    private String roleId;\n    private String roleName;\n    private String roleLevel;\n    private long roleCreateTime;\n    private String roleVipLevel;\n    private long roleUpLevelTime;\n    private String roleUnionName;\n    private float roleBalance ;\n\n    //区服信息\n    private String serverId;\n    private String serverName;\n\n    private String extraInfo;\n\n    public void setReportId(int reportId) {\n        ReportId = reportId;\n    }\n\n    public void setRoleId(String roleId) {\n        this.roleId = roleId;\n    }\n\n    public void setRoleName(String roleName) {\n        this.roleName = roleName;\n    }\n\n    public void setRoleLevel(String roleLevel) {\n        this.roleLevel = roleLevel;\n    }\n\n    public void setRoleCreateTime(long roleCreateTime) {\n        this.roleCreateTime = roleCreateTime;\n    }\n\n    public void setRoleVipLevel(String roleVipLevel) {\n        this.roleVipLevel = roleVipLevel;\n    }\n\n    public void setRoleUpLevelTime(long roleUpLevelTime) {\n        this.roleUpLevelTime = roleUpLevelTime;\n    }\n\n    public void setRoleUnionName(String roleUnionName) {\n        this.roleUnionName = roleUnionName;\n    }\n\n    public void setRoleBalance(float roleBalance) {\n        this.roleBalance = roleBalance;\n    }\n\n    public void setServerId(String serverId) {\n        this.serverId = serverId;\n    }\n\n    public void setServerName(String serverName) {\n        this.serverName = serverName;\n    }\n\n    public void setExtraInfo(String extraInfo) {\n        this.extraInfo = extraInfo;\n    }\n}\n"
  },
  {
    "path": "GameSDK_API/src/main/java/com/bzai/gamesdk/bean/params/PayParams.java",
    "content": "package com.bzai.gamesdk.bean.params;\n\n/**\n * Created by bzai on 2018/4/13.\n * <p>\n * Desc:\n *\n *  支付接口的透传实体类,只提供set方法，不对外提供get方法\n *\n *  注意：字段需与服务端一致，防止后续自动转化时出问题\n *\n *  productID\t\t\t商品ID\n *  productName\t\t\t商品名称\n *  productDesc\t\t\t商品描述\n *  productNumber       商品数量 (暂时没有)\n *\n *  money\t\t\t\t商品单价 (以分为单位)\n *  coinName\t\t\t货币名称(人民币/台币/美元..) (暂时没有)\n *\tcoinRate\t\t\t货币对人民币的比例 (暂时没有)\n *\n *  roleID              当前游戏内角色ID\n *  roleName            当前游戏内角色名称\n *  roleLevel           玩家等级\n *  serverID            当前玩家所在的服务器ID\n *  serverName          当前玩家所在的服务器名称\n *\n *  orderNo\t\t\t\t游戏的订单号 (暂时没有)\n *  rate                游戏币与人民币比例  (暂时没有)\n *  callback            支付回调地址\n *\textension\t\t\t透传给 cp服务器的字段\n *\n *  gorder              CP订单号\n */\n\npublic class PayParams {\n\n    //商品信息\n    private String productID;\n    private String productName;\n    private String productDesc;\n\n    //金额信息\n    private int money;\n\n    //玩家信息\n    private String roleID;\n    private String roleName;\n    private String roleLevel;\n    private String serverID;\n    private String serverName;\n\n    //支付配置信息\n    private String callback;\n    private String extension;\n\n    //游戏订单号\n    private String gorder;\n\n    public void setProductId(String productId) {\n        this.productID = productId;\n    }\n\n    public void setProductName(String productName) {\n        this.productName = productName;\n    }\n\n    public void setProductDesc(String productDesc) {\n        this.productDesc = productDesc;\n    }\n\n    public void setMoney(int money) {\n        this.money = money;\n    }\n\n    public void setRoleID(String roleID) {\n        this.roleID = roleID;\n    }\n\n    public void setRoleName(String roleName) {\n        this.roleName = roleName;\n    }\n\n    public void setRoleLevel(String roleLevel) {\n        this.roleLevel = roleLevel;\n    }\n\n    public void setServerID(String serverID) {\n        this.serverID = serverID;\n    }\n\n    public void setServerName(String serverName) {\n        this.serverName = serverName;\n    }\n\n    public void setNotifyUrl(String callback) {\n        this.callback = callback;\n    }\n\n    public void setExtension(String extension) {\n        this.extension = extension;\n    }\n\n    public void setGorder(String gorder) {\n        this.gorder = gorder;\n    }\n}\n"
  },
  {
    "path": "GameSDK_API/src/main/java/com/bzai/gamesdk/listener/AccountCallBackLister.java",
    "content": "package com.bzai.gamesdk.listener;\n\n/**\n * Created by bzai on 2018/4/12.\n * <p>\n * Desc:\n *\n *  对外的SDK Api 账号监听接口\n *\n */\n\npublic interface AccountCallBackLister {\n\n    int LOGIN_SUCCESS = 1000; //登录成功\n    int LOGIN_FAILURE = 1001; //登录失败\n    int LOGIN_CANCEL = 1002;  //登录取消\n\n    int SWITCH_ACCOUNT_SUCCESS = 1003; //切换账号成功\n    int SWITCH_ACCOUNT_FAILURE = 1004; //切换账号失败\n    int SWITCH_ACCOUNT_CANCEL = 1005; //切换账号取消\n\n    int LOGOUT_SUCCESS = 1006; //注销账号成功\n    int LOGOUT_FAILURE = 1007; //注销账号失败\n    int LOGOUT_CANCEL = 1008; //注销账号取消\n\n    void onAccountEventCallBack(String jsonStr);\n\n}\n"
  },
  {
    "path": "GameSDK_API/src/main/java/com/bzai/gamesdk/listener/ExitCallBackLister.java",
    "content": "package com.bzai.gamesdk.listener;\n\n/**\n * Created by bzai on 2018/4/11.\n * <p>\n * Desc:\n * 对外的SDK Api 退出监听接口\n */\n\npublic interface ExitCallBackLister {\n\n    /**\n     * 退出框退出成功回调\n     */\n    void onExitDialogSuccess();\n\n    /**\n     * 退出框退出取消回调\n     */\n    void onExitDialogCancel();\n\n    /**\n     * 不存在退出框，需要游戏自己实现退出框\n     */\n    void onNotExitDialog();\n}\n"
  },
  {
    "path": "GameSDK_API/src/main/java/com/bzai/gamesdk/listener/InitCallBackLister.java",
    "content": "package com.bzai.gamesdk.listener;\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc:\n *\n *  对外的SDK Api 初始化监听接口\n */\n\npublic interface InitCallBackLister {\n\n    /**\n     * 初始化成功\n     */\n    void onSuccess();\n\n    /**\n     * 初始化失败\n     * @param errCode\n     * @param msg\n     */\n    void onFailure(int errCode, String msg);\n\n\n}\n"
  },
  {
    "path": "GameSDK_API/src/main/java/com/bzai/gamesdk/listener/PurchaseCallBackListener.java",
    "content": "package com.bzai.gamesdk.listener;\n\n/**\n * Created by bzai on 2018/4/13.\n * <p>\n * Desc:\n *\n * 支付回调\n *\n */\n\npublic interface PurchaseCallBackListener {\n\n    /**\n     * 返回订单成功信息,比支付结果早\n     * @param orderId\n     */\n    void onOrderId(String orderId);\n\n    /**\n     * 支付成功\n     */\n    void onSuccess();\n\n    /**\n     * 支付失败回调\n     * @param errCode\n     * @param msg 失败信息\n     *\n     */\n    void onFailure(int errCode, String msg);\n\n    /**\n     * 支付取消\n     */\n    void onCancel();\n\n\n    /**\n     * 支付完成，当渠道没有正确支付回调时，会返回该结果\n     */\n    void onComplete();\n}\n"
  },
  {
    "path": "GameSDK_API/src/test/java/com/bzai/gamesdk/api/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdk.api;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_Custom/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_Custom/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDK_Module_Account')\n    compile project(':GameSDK_Module_Init')\n    compile project(':GameSDK_Module_Purchase')\n}\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_Custom/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_Custom/src/androidTest/java/com/bzai/gamesdk/project/channel/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdk.project.channel;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdk.project.channel.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_Custom/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.project.channel\" />\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_Custom/src/main/assets/Plugin_config.txt",
    "content": "{\n    \"plugin\": [\n        {\n            \"plugin_name\": \"plugin_wechat\",\n            \"class_name\": \"com.bzai.gamesdk.plugin.wechat.WechatPlugin\",\n            \"description\": \"微信功能插件\",\n            \"version\": \"5.1.4\"\n        },\n        {\n            \"plugin_name\": \"plugin_alipay\",\n            \"class_name\": \"com.bzai.gamesdk.plugin.alipay.AlipayPlugin\",\n            \"description\": \"支付宝功能插件\",\n            \"version\": \"15.5.5\"\n        }\n    ]\n}"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_Custom/src/main/assets/Project_config.txt",
    "content": "{\n    \"project\": [\n        {\n            \"project_name\": \"project\",\n            \"class_name\": \"com.bzai.gamesdk.project.CustomProject\",\n            \"description\": \"自定义SDK项目\",\n            \"version\": \"1.0.0\"\n        }\n    ]\n}"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_Custom/src/main/assets/SDKInfo.json",
    "content": "{\n  \"sdk_type\": \"1\",\n  \"sdk_name\": \"SDK_Custom\",\n  \"sdk_version\": \"1.0.0\",\n  \"sdk_url\": \"http://www.baidu.com/\"\n}"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_Custom/src/main/java/com/bzai/gamesdk/project/CustomProject.java",
    "content": "package com.bzai.gamesdk.project;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.widget.Toast;\n\nimport com.bzai.gamesdk.common.utils_base.config.ErrCode;\nimport com.bzai.gamesdk.common.utils_base.config.TypeConfig;\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.parse.project.Project;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\nimport com.bzai.gamesdk.module.account.AccountManager;\nimport com.bzai.gamesdk.module.account.bean.AccountCallBackBean;\nimport com.bzai.gamesdk.module.init.InitManager;\nimport com.bzai.gamesdk.module.purchase.PurchaseManager;\n\nimport java.util.HashMap;\n\n/**\n * Created by bzai on 2018/7/10.\n * <p>\n * Desc:\n *\n *    模拟自定义SDK项目\n *\n *    (注意生命周期方法必接，且必须初始化后才调用渠道、功能插件的生命周期方法)\n */\n\npublic class CustomProject extends Project{\n\n    private final String TAG = getClass().getSimpleName();\n\n\n    /**\n     * 项目实例化入口\n     */\n    @Override\n    protected synchronized void initProject() {\n        LogUtils.d(TAG, getClass().getSimpleName() + \" has init\");\n        super.initProject();\n    }\n\n\n    /******************************************      初始化      ****************************************/\n\n    @Override\n    public void init(Activity activity, String gameid, String gamekey, final CallBackListener callBackListener) {\n        LogUtils.d(TAG,\"init\");\n\n        if (activity == null || callBackListener == null) {\n            callBackListener.onFailure(ErrCode.PARAMS_ERROR,\"activity or callBackListener is null\");\n            return;\n        }\n\n        //设置账号监听\n        AccountManager.getInstance().setLoginCallBackLister(projectAccountCallBackListener);\n\n        InitManager.getInstance().init(activity, gameid, gamekey, new CallBackListener() {\n            @Override\n            public void onSuccess(Object object) {\n                callBackListener.onSuccess(null);\n            }\n\n            @Override\n            public void onFailure(int code, String msg) {\n                callBackListener.onFailure(code,msg);\n            }\n        });\n    }\n\n\n    /******************************************      账号      ****************************************/\n\n    /*** SDKApi层设置回调监听 */\n    private CallBackListener ApiAccountCallback;\n\n    @Override\n    public void setAccountCallBackLister(CallBackListener callBackLister) {\n        ApiAccountCallback = callBackLister;\n    }\n\n    /**\n     * 监听AccountManager登录、切换账号、绑定、注销的回调信息\n     */\n    private CallBackListener projectAccountCallBackListener = new CallBackListener<AccountCallBackBean>() {\n\n        @Override\n        public void onSuccess(AccountCallBackBean callBackBean) {\n            ApiAccountCallback.onSuccess(callBackBean);\n        }\n\n        @Override\n        public void onFailure(int code, String msg) {\n            //不会走到这里来\n        }\n    };\n\n    private void AccountOnFailCallBack(int event, int code, String msg){\n\n        AccountCallBackBean callBackBean = new AccountCallBackBean();\n        callBackBean.setEvent(event);\n        callBackBean.setErrorCode(code);\n        callBackBean.setMsg(msg);\n        ApiAccountCallback.onSuccess(callBackBean);\n    }\n\n\n    @Override\n    public void login(Activity activity, HashMap<String, Object> loginParams) {\n        LogUtils.d(TAG,\"login\");\n\n        if (!InitManager.getInstance().getInitState()){\n            Toast.makeText(activity,\"请先初始化\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        if (activity == null ) {\n            AccountOnFailCallBack(TypeConfig.LOGIN,ErrCode.PARAMS_ERROR,\"activity is null\");\n            return;\n        }\n\n        AccountManager.getInstance().showLoginView(activity,loginParams);\n    }\n\n\n    @Override\n    public void switchAccount(Activity activity) {\n        LogUtils.d(TAG,\"switchAccount\");\n\n        if (!InitManager.getInstance().getInitState()){\n            Toast.makeText(activity,\"请先初始化\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        if (!AccountManager.getInstance().getLoginState()){\n            AccountOnFailCallBack(TypeConfig.SWITCHACCOUNT,ErrCode.NO_LOGIN,\"account has not login\");\n            return;\n        }\n\n        if (activity == null ) {\n            AccountOnFailCallBack(TypeConfig.LOGIN,ErrCode.PARAMS_ERROR,\"activity is null\");\n            return;\n        }\n\n        AccountManager.getInstance().switchAccount(activity);\n    }\n\n    @Override\n    public void logout(Activity activity) {\n        LogUtils.d(TAG,\"logout\");\n\n        if (!InitManager.getInstance().getInitState()){\n            Toast.makeText(activity,\"请先初始化\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        if (!AccountManager.getInstance().getLoginState()){\n            AccountOnFailCallBack(TypeConfig.LOGOUT,ErrCode.NO_LOGIN,\"account has not login\");\n            return;\n        }\n\n        if (activity == null ) {\n            AccountOnFailCallBack(TypeConfig.LOGIN,ErrCode.PARAMS_ERROR,\"activity is null\");\n            return;\n        }\n\n        AccountManager.getInstance().logout(activity);\n    }\n\n\n    /******************************************      购买      ****************************************/\n\n\n    @Override\n    public void pay(Activity activity, HashMap<String, Object> payParams, CallBackListener callBackListener) {\n        LogUtils.d(TAG,\"pay\");\n\n        if (!InitManager.getInstance().getInitState()){\n            Toast.makeText(activity,\"请先初始化\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        if (!AccountManager.getInstance().getLoginState()){\n            callBackListener.onFailure(ErrCode.NO_LOGIN,\"account has not login\");\n            return;\n        }\n\n        if (activity == null || payParams == null || callBackListener == null) {\n            callBackListener.onFailure(ErrCode.PARAMS_ERROR,\"activity or PayParams or callBackListener is null\");\n            return;\n        }\n\n        PurchaseManager.getInstance().showPayView(activity,payParams,callBackListener);\n    }\n\n\n    /******************************************      退出      ****************************************/\n\n\n    /**\n     * 退出SDK\n     */\n    @Override\n    public void exit(Activity activity, CallBackListener callBackListener) {\n        LogUtils.d(TAG,\"exit\");\n\n        if (activity == null || callBackListener == null) {\n            callBackListener.onFailure(ErrCode.PARAMS_ERROR,\"activity or callBackListener is null\");\n            return;\n        }\n\n        callBackListener.onFailure(ErrCode.NO_EXIT_DIALOG,\"channel not exitDialog\");\n    }\n\n\n    /*************************************  生命周期接口(必接) ****************************************/\n\n    @Override\n    public void onCreate(Activity activity, Bundle savedInstanceState) {\n        LogUtils.d(TAG,\"onCreate\");\n\n        if (InitManager.getInstance().getInitState()){\n            super.onCreate(activity, savedInstanceState);\n        }\n    }\n\n    @Override\n    public void onStart(Activity activity) {\n        LogUtils.d(TAG,\"onStart\");\n\n        if (InitManager.getInstance().getInitState()){\n            super.onStart(activity);\n        }\n    }\n\n    @Override\n    public void onResume(Activity activity) {\n        LogUtils.d(TAG,\"onResume\");\n\n        if (InitManager.getInstance().getInitState()){\n            super.onResume(activity);\n        }\n    }\n\n    @Override\n    public void onPause(Activity activity) {\n        LogUtils.d(TAG,\"onPause\");\n\n        if (InitManager.getInstance().getInitState()){\n            super.onPause(activity);\n        }\n    }\n\n    @Override\n    public void onStop(Activity activity) {\n        LogUtils.d(TAG,\"onStop\");\n\n        if (InitManager.getInstance().getInitState()){\n            super.onStop(activity);\n        }\n    }\n\n    @Override\n    public void onDestroy(Activity activity) {\n        LogUtils.d(TAG,\"onDestroy\");\n\n        if (InitManager.getInstance().getInitState()){\n            super.onDestroy(activity);\n        }\n    }\n\n    @Override\n    public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {\n        LogUtils.d(TAG,\"onActivityResult\");\n\n        if (InitManager.getInstance().getInitState()){\n            super.onActivityResult(activity, requestCode, resultCode, data);\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(Activity activity, int requestCode, String[] permissions,int[] grantResults) {\n        LogUtils.d(TAG,\"onRequestPermissionsResult\");\n\n        if (InitManager.getInstance().getInitState()){\n            super.onRequestPermissionsResult(activity, requestCode, permissions, grantResults);\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_Custom/src/main/java/com/bzai/gamesdk/project/ProjectApplication.java",
    "content": "package com.bzai.gamesdk.project;\n\nimport android.app.Application;\nimport android.content.Context;\n\nimport com.bzai.gamesdk.module.init.InitManager;\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc: 项目SDK的application\n */\npublic class ProjectApplication extends Application {\n\n    @Override\n    protected void attachBaseContext(Context context) {\n        //必须先加载项目配置文件，找到项目的入口。\n        InitManager.getInstance().initApplication(this,context,true);\n        super.attachBaseContext(context);\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_Custom/src/test/java/com/bzai/gamesdk/project/channel/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdk.project.channel;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_JuHe/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_JuHe/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDK_Channel_Lexiang')\n    compile project(':GameSDK_Module_Init')\n    compile project(':GameSDK_Module_Account')\n    compile project(':GameSDK_Module_Purchase')\n}\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_JuHe/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_JuHe/src/androidTest/java/com/bzai/gamesdk/project/juhe/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdk.project.juhe;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdk.project.juhe.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_JuHe/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.project.juhe\" />\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_JuHe/src/main/assets/Plugin_config.txt",
    "content": "{\n    \"plugin\": [\n        {\n            \"plugin_name\": \"plugin_wechat\",\n            \"class_name\": \"com.bzai.gamesdk.plugin.wechat.WechatPlugin\",\n            \"description\": \"微信功能插件\",\n            \"version\": \"5.1.4\"\n        },\n        {\n            \"plugin_name\": \"plugin_alipay\",\n            \"class_name\": \"com.bzai.gamesdk.plugin.alipay.AlipayPlugin\",\n            \"description\": \"支付宝功能插件\",\n            \"version\": \"15.5.5\"\n        }\n    ]\n}"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_JuHe/src/main/assets/Project_config.txt",
    "content": "{\n    \"project\": [\n        {\n            \"project_name\": \"project\",\n            \"class_name\": \"com.bzai.gamesdk.project.JuHeProject\",\n            \"description\": \"聚合SDK项目\",\n            \"version\": \"1.0.0\"\n        }\n    ]\n}"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_JuHe/src/main/assets/SDKInfo.json",
    "content": "{\n  \"sdk_type\": \"1\",\n  \"sdk_name\": \"SDK_JuHe\",\n  \"sdk_version\": \"1.0.0\",\n  \"sdk_url\": \"http://www.baidu.com/\"\n}"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_JuHe/src/main/java/com/bzai/gamesdk/project/JuHeProject.java",
    "content": "package com.bzai.gamesdk.project;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.widget.Toast;\n\nimport com.bzai.gamesdk.common.utils_base.config.ErrCode;\nimport com.bzai.gamesdk.common.utils_base.config.TypeConfig;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonObject;\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.parse.channel.Channel;\nimport com.bzai.gamesdk.common.utils_base.parse.channel.ChannelManager;\nimport com.bzai.gamesdk.common.utils_base.parse.project.Project;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\nimport com.bzai.gamesdk.common.utils_business.cache.BaseCache;\nimport com.bzai.gamesdk.module.account.AccountManager;\nimport com.bzai.gamesdk.module.account.bean.AccountCallBackBean;\nimport com.bzai.gamesdk.module.init.InitManager;\nimport com.bzai.gamesdk.module.purchase.PurchaseManager;\nimport com.bzai.gamesdk.module.purchase.PurchaseResult;\n\nimport java.util.HashMap;\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc:\n *\n *  (业务逻辑判断)\n *  JuHeProject 聚合SDK的项目入口类。\n *\n *  (注意生命周期方法必接，且必须初始化后才调用渠道、功能插件的生命周期方法)\n *\n */\n\npublic class JuHeProject extends Project {\n\n    private final String TAG = getClass().getSimpleName();\n\n    //渠道对象\n    private Channel channel;\n\n    private Activity mActivity;\n\n    /**\n     * 表明项目入口已实例化,可以正常加载走SDK后续功能逻辑\n     */\n    @Override\n    protected void initProject() {\n        LogUtils.d(TAG, getClass().getSimpleName() + \" has init\");\n        super.initProject();\n    }\n\n\n    /******************************************  初始化   ****************************************/\n\n\n    @Override\n    public void init(final Activity activity, String gameid, String gamekey, final CallBackListener callBackListener) {\n        LogUtils.d(TAG,\"init\");\n\n        if (activity == null || callBackListener == null) {\n            callBackListener.onFailure(ErrCode.PARAMS_ERROR,\"activity or callBackListener 为空\");\n            return;\n        }\n\n        //设置账号监听\n        AccountManager.getInstance().setLoginCallBackLister(projectAccountCallBackListener);\n\n        InitManager.getInstance().init(activity, gameid, gamekey, new CallBackListener() {\n\n            @Override\n            public void onSuccess(Object o) {\n\n                channel = ChannelManager.getInstance().getChannel(); //注意渠道配置文件有没有加载\n\n                channel.init(activity, null, new CallBackListener() {\n\n                    @Override\n                    public void onSuccess(Object o) {\n\n                        //项目SDK初始化成功后，调用渠道SDK初始化。\n                        InitManager.getInstance().setInitState(true);\n                        callBackListener.onSuccess(o);\n                    }\n\n                    @Override\n                    public void onFailure(int code, String msg) {\n                        InitManager.getInstance().setInitState(false);\n                        callBackListener.onFailure(code,msg);\n                    }\n                });\n            }\n\n            @Override\n            public void onFailure(int code, String msg) {\n                callBackListener.onFailure(code,msg);\n            }\n        });\n    }\n\n\n    /******************************************      账号      ****************************************/\n\n\n    /*** SDKApi层设置回调监听*/\n    private CallBackListener ApiAccountCallback;\n\n    @Override\n    public void setAccountCallBackLister(CallBackListener callBackLister) {\n        ApiAccountCallback = callBackLister;\n    }\n\n    /**\n     * 监听AccountManager登录、切换账号、绑定、注销的回调信息\n     */\n    private CallBackListener projectAccountCallBackListener = new CallBackListener<AccountCallBackBean>() {\n\n        @Override\n        public void onSuccess(AccountCallBackBean callBackBean) {\n            ApiAccountCallback.onSuccess(callBackBean);\n        }\n\n        @Override\n        public void onFailure(int code, String msg) {\n            //不会走到这里来\n        }\n    };\n\n    private void AccountOnFailCallBack(int event, int code, String msg){\n\n        AccountCallBackBean callBackBean = new AccountCallBackBean();\n        callBackBean.setEvent(event);\n        callBackBean.setErrorCode(code);\n        callBackBean.setMsg(msg);\n        ApiAccountCallback.onSuccess(callBackBean);\n    }\n\n\n    /**\n     * 监听渠道Channel的登录、切换账号、绑定、注销的回调信息\n     */\n    private CallBackListener authCallBackListener = new CallBackListener<HashMap<String,Object>>() {\n\n\n        @Override\n        public void onSuccess(HashMap<String,Object> loginAuthData) {\n            LogUtils.debug_d(TAG,channel.getClass().getSimpleName() + \" = \" + loginAuthData.toString());\n\n            int type = (int) loginAuthData.get(Channel.PARAMS_OAUTH_TYPE);\n            //类型为登录、切换账号就走服务器登录逻辑\n            if (type == TypeConfig.LOGIN || type == TypeConfig.SWITCHACCOUNT){\n                AccountManager.getInstance().authLogin(mActivity,loginAuthData);\n\n            } else if (type == TypeConfig.LOGOUT){ //类型为登出\n                AccountManager.getInstance().logout(mActivity);\n            }\n        }\n\n        @Override\n        public void onFailure(int code, String msg) {\n            LogUtils.debug_d(TAG,channel.getClass().getSimpleName() + msg);\n            //做失败处理\n            switch (code){\n                case ErrCode.CHANNEL_LOGIN_FAIL: //登录失败\n                    AccountOnFailCallBack(TypeConfig.LOGIN, ErrCode.FAILURE,msg);\n                    break;\n\n                case ErrCode.CHANNEL_LOGIN_CANCEL: //登录取消\n                    AccountOnFailCallBack(TypeConfig.LOGIN, ErrCode.CANCEL,msg);\n                    break;\n\n                case ErrCode.CHANNEL_SWITCH_ACCOUNT_FAIL: //切换账号失败\n                    AccountOnFailCallBack(TypeConfig.SWITCHACCOUNT, ErrCode.FAILURE,msg);\n                    break;\n\n                case ErrCode.CHANNEL_SWITCH_ACCOUNT_CANCEL: //切换账号取消\n                    AccountOnFailCallBack(TypeConfig.SWITCHACCOUNT, ErrCode.CANCEL,msg);\n                    break;\n\n                case ErrCode.CHANNEL_LOGOUT_FAIL:// 注销失败\n                    AccountOnFailCallBack(TypeConfig.LOGOUT, ErrCode.FAILURE,msg);\n                    break;\n\n                case ErrCode.CHANNEL_LOGOUT_CANCEL: //注销取消\n                    AccountOnFailCallBack(TypeConfig.LOGOUT, ErrCode.CANCEL,msg);\n                    break;\n            }\n        }\n    };\n\n    @Override\n    public void login(Activity activity, HashMap<String, Object> loginParams) {\n        LogUtils.d(TAG,\"login\");\n\n        if (!InitManager.getInstance().getInitState()){\n            Toast.makeText(activity,\"请先初始化\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        if (activity == null ) {\n            AccountOnFailCallBack(TypeConfig.LOGIN,ErrCode.PARAMS_ERROR,\"activity 为空\");\n            return;\n        }\n\n        mActivity = activity;\n        channel.login(activity, loginParams, authCallBackListener);\n    }\n\n\n\n    @Override\n    public void switchAccount(Activity activity) {\n        LogUtils.d(TAG,\"switchAccount\");\n\n        if (!InitManager.getInstance().getInitState()){\n            Toast.makeText(activity,\"请先初始化\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        if (!AccountManager.getInstance().getLoginState()){\n            AccountOnFailCallBack(TypeConfig.SWITCHACCOUNT,ErrCode.NO_LOGIN,\"account has not login\");\n            return;\n        }\n\n        if (activity == null ) {\n            AccountOnFailCallBack(TypeConfig.SWITCHACCOUNT,ErrCode.PARAMS_ERROR,\"activity 为空\");\n            return;\n        }\n\n        mActivity = activity;\n\n        if (isSupport(TypeConfig.FUNC_SWITCHACCOUNT)){\n            channel.switchAccount(activity,authCallBackListener);\n\n        }else {\n            Toast.makeText(activity,\"没有实现该方法\",Toast.LENGTH_SHORT).show();\n        }\n    }\n\n\n\n    @Override\n    public void logout(Activity activity) {\n        LogUtils.d(TAG,\"logout\");\n\n        if (!InitManager.getInstance().getInitState()){\n            Toast.makeText(activity,\"请先初始化\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        if (!AccountManager.getInstance().getLoginState()){\n            AccountOnFailCallBack(TypeConfig.LOGOUT,ErrCode.NO_LOGIN,\"account has not login\");\n            return;\n        }\n\n        if (activity == null ) {\n            AccountOnFailCallBack(TypeConfig.LOGIN,ErrCode.PARAMS_ERROR,\"activity 为空\");\n            return;\n        }\n\n        if (isSupport(TypeConfig.FUNC_LOGOUT)){\n            channel.logout(activity, authCallBackListener);\n\n        }else {\n            Toast.makeText(activity,\"没有实现该方法\",Toast.LENGTH_SHORT).show();\n        }\n    }\n\n\n    /******************************************      购买      ****************************************/\n\n    @Override\n    public void pay(final Activity activity, final HashMap<String, Object> payParams, final CallBackListener callBackListener) {\n        LogUtils.d(TAG,\"pay\");\n\n        if (!InitManager.getInstance().getInitState()){\n            Toast.makeText(activity,\"请先初始化\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        if (!AccountManager.getInstance().getLoginState()){\n            callBackListener.onFailure(ErrCode.NO_LOGIN,\"account has not login\");\n            return;\n        }\n\n        if (activity == null || callBackListener == null) {\n            callBackListener.onFailure(ErrCode.PARAMS_ERROR,\"activity or callBackListener is null\");\n            return;\n        }\n\n        //先创建订单\n        PurchaseManager.getInstance().createOrderId(activity, payParams, new CallBackListener() {\n\n            @Override\n            public void onSuccess(Object object) {\n\n                //返回订单号\n                String orderID = (String) object;\n\n                //创建订单成功，回调订单信息和CP的透传信息\n                JsonObject jsonObject = new JsonObject();\n                jsonObject.addProperty(\"orderId\",orderID);\n                PurchaseResult purchaseResult = new PurchaseResult(PurchaseResult.OrderState,jsonObject);\n                callBackListener.onSuccess(purchaseResult);\n\n                payParams.put(\"orderId\",orderID);\n\n                channel.pay(activity, payParams, new CallBackListener() {\n\n                    @Override\n                    public void onSuccess(Object object) {\n\n                        //支付结果回调到这里来\n                        PurchaseResult purchaseResult = new PurchaseResult(PurchaseResult.PurchaseState,null);\n                        callBackListener.onSuccess(purchaseResult);\n\n                    }\n\n                    @Override\n                    public void onFailure(int code, String msg) {\n                        callBackListener.onFailure(code,msg);\n                    }\n                });\n\n            }\n\n            @Override\n            public void onFailure(int code, String msg) {\n                callBackListener.onFailure(code,\"create orderId fail\");\n            }\n        });\n\n    }\n\n\n    @Override\n    public void showFloatView(Activity activity) {\n        LogUtils.d(TAG,\"showFloatView\");\n\n        if (!InitManager.getInstance().getInitState()){\n            Toast.makeText(activity,\"请先初始化\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        mActivity = activity;\n\n        if (isSupport(TypeConfig.FUNC_SHOW_FLOATWINDOW)){\n            channel.showFloatView(activity);\n\n        }else {\n            Toast.makeText(activity,\"没有实现该方法\",Toast.LENGTH_SHORT).show();\n        }\n\n    }\n\n    @Override\n    public void dismissFloatView(Activity activity) {\n        LogUtils.d(TAG,\"dismissFloatView\");\n\n        if (!InitManager.getInstance().getInitState()){\n            Toast.makeText(activity,\"请先初始化\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        mActivity = activity;\n\n        if (isSupport(TypeConfig.FUNC_DISMISS_FLOATWINDOW)){\n            channel.dismissFloatView(activity);\n\n        }else {\n            Toast.makeText(activity,\"没有实现该方法\",Toast.LENGTH_SHORT).show();\n        }\n    }\n\n\n    @Override\n    public void exit(Activity activity, CallBackListener callBackListener) {\n        LogUtils.d(TAG,\"exit\");\n\n        if (activity == null || callBackListener == null) {\n            callBackListener.onFailure(ErrCode.PARAMS_ERROR,\"activity or callBackListener is null\");\n            return;\n        }\n\n        mActivity = activity;\n\n        channel.exit(activity,callBackListener);\n    }\n\n    @Override\n    public void reportData(Context context, HashMap<String, Object> dataMap) {\n        LogUtils.d(TAG,\"reportData\");\n\n        if (!InitManager.getInstance().getInitState()){\n            Toast.makeText(context,\"请先初始化\",Toast.LENGTH_SHORT).show();\n            return;\n        }\n\n        channel.reportData(context,dataMap);\n    }\n\n\n    @Override\n    public void extendFunction(Activity activity, int functionType, Object object, CallBackListener callBackListener) {\n        super.extendFunction(activity, functionType, object, callBackListener);\n    }\n\n\n    /**\n     * 是否支持该接口,由于个别渠道只简单实现登录、支付接口\n     * @param FuncType\n     * @return\n     */\n    public boolean isSupport(int FuncType) {\n        return channel.isSupport(FuncType);\n    }\n\n\n    @Override\n    public String getChannelID() {\n        return BaseCache.getInstance().getChannelId();\n    }\n\n    /*************************************  生命周期接口 ****************************************/\n\n    @Override\n    public void onCreate(Activity activity, Bundle savedInstanceState) {\n        LogUtils.d(TAG,\"onCreate\");\n\n        if (InitManager.getInstance().getInitState()){\n            super.onCreate(activity, savedInstanceState);\n            channel.onCreate(activity,savedInstanceState);\n        }\n    }\n\n    @Override\n    public void onStart(Activity activity) {\n        LogUtils.d(TAG,\"onStart\");\n        if (InitManager.getInstance().getInitState()){\n            super.onStart(activity);\n            channel.onStart(activity);\n        }\n    }\n\n    @Override\n    public void onResume(Activity activity) {\n        LogUtils.d(TAG,\"onResume\");\n\n        if (InitManager.getInstance().getInitState()){\n            super.onResume(activity);\n            channel.onResume(activity);\n        }\n    }\n\n    @Override\n    public void onPause(Activity activity) {\n        LogUtils.d(TAG,\"onPause\");\n        if (InitManager.getInstance().getInitState()){\n            super.onPause(activity);\n            channel.onPause(activity);\n        }\n    }\n\n    @Override\n    public void onStop(Activity activity) {\n        LogUtils.d(TAG,\"onStop\");\n        if (InitManager.getInstance().getInitState()){\n            super.onStop(activity);\n            channel.onStop(activity);\n        }\n    }\n\n    @Override\n    public void onDestroy(Activity activity) {\n        LogUtils.d(TAG,\"onDestroy\");\n        if (InitManager.getInstance().getInitState()){\n            super.onDestroy(activity);\n            channel.onDestroy(activity);\n        }\n    }\n\n    @Override\n    public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {\n        LogUtils.d(TAG,\"onActivityResult\");\n        if (InitManager.getInstance().getInitState()){\n            super.onActivityResult(activity, requestCode, resultCode, data);\n            channel.onActivityResult(activity,requestCode,resultCode,data);\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(Activity activity, int requestCode, String[] permissions,int[] grantResults) {\n        LogUtils.d(TAG,\"onRequestPermissionsResult\");\n        if (InitManager.getInstance().getInitState()){\n            super.onRequestPermissionsResult(activity, requestCode, permissions, grantResults);\n            channel.onRequestPermissionsResult(activity,requestCode,permissions,grantResults);\n        }\n    }\n\n    /*************************************  生命周期接口 ****************************************/\n}\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_JuHe/src/main/java/com/bzai/gamesdk/project/ProjectApplication.java",
    "content": "package com.bzai.gamesdk.project;\n\nimport android.content.Context;\nimport com.bzai.gamesdk.channel.application.ChannelApplication;\nimport com.bzai.gamesdk.module.init.InitManager;\n\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc: 项目SDK的application\n *\n *     ProjectApplication extends ChannelApplication\n */\npublic class ProjectApplication extends ChannelApplication {\n\n    @Override\n    protected void attachBaseContext(Context context) {\n        //必须先加载项目配置文件，找到项目的入口。\n        InitManager.getInstance().initApplication(this,context,true);\n        super.attachBaseContext(context);\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_BeginProject/GameSDK_Project_JuHe/src/test/java/com/bzai/gamesdk/project/juhe/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdk.project.juhe;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDK_Utils')\n\n}\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/androidTest/java/com/bzai/gamesdk/channel/test/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdk.channel.test;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdk.channel.test.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.channel.lexiang\" >\n\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n\n\n    <application\n        android:allowBackup=\"true\">\n\n        <activity\n            android:name=\"com.youxun.sdk.app.YouxunWebViewActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:screenOrientation=\"landscape\"\n            android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\" />\n        <activity\n            android:name=\"com.youxun.sdk.app.NewLoginActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:screenOrientation=\"landscape\"\n            android:theme=\"@android:style/Theme.Translucent.NoTitleBar.Fullscreen\" />\n        <activity\n            android:name=\"com.youxun.sdk.app.BoundActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:screenOrientation=\"landscape\"\n            android:theme=\"@android:style/Theme.Translucent.NoTitleBar.Fullscreen\" />\n        <activity\n            android:name=\"com.youxun.sdk.app.MobileAccountActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:screenOrientation=\"landscape\"\n            android:theme=\"@android:style/Theme.Translucent.NoTitleBar.Fullscreen\" />\n        <activity\n            android:name=\"com.youxun.sdk.app.YouxunAccountActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:screenOrientation=\"landscape\"\n            android:theme=\"@android:style/Theme.Translucent.NoTitleBar.Fullscreen\" />\n        <activity\n            android:name=\"com.youxun.sdk.app.GiftBagActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:screenOrientation=\"landscape\"\n            android:theme=\"@android:style/Theme.Translucent.NoTitleBar.Fullscreen\" />\n        <activity\n            android:name=\"com.youxun.sdk.app.PayActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:screenOrientation=\"landscape\"\n            android:theme=\"@android:style/Theme.Black.NoTitleBar\" />\n\n        <activity\n            android:name=\"com.alipay.sdk.app.H5PayActivity\"\n            android:configChanges=\"orientation|keyboardHidden|navigation|screenSize\"\n            android:exported=\"false\"\n            android:screenOrientation=\"behind\"\n            android:windowSoftInputMode=\"adjustResize|stateHidden\" />\n        <activity\n            android:name=\"com.alipay.sdk.auth.AuthActivity\"\n            android:configChanges=\"orientation|keyboardHidden|navigation\"\n            android:exported=\"false\"\n            android:screenOrientation=\"behind\" />\n        <!-- heepay -->\n        <activity\n            android:name=\"com.heepay.plugin.activity.WeChatNotityActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:screenOrientation=\"behind\"\n            android:theme=\"@android:style/Theme.Translucent.NoTitleBar\" />\n\n\n    </application>\n\n</manifest>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/assets/Channel_config.txt",
    "content": "{\n    \"channel\": [\n        {\n            \"channel_name\": \"channel\",\n            \"class_name\": \"com.bzai.gamesdk.channel.lexiang.LexiangSDK\",\n            \"description\": \"乐享渠道SDK\",\n            \"version\": \"1.0.0\"\n        }\n    ]\n}"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/java/com/bzai/gamesdk/channel/application/ChannelApplication.java",
    "content": "package com.bzai.gamesdk.channel.application;\n\nimport android.app.Application;\nimport android.content.Context;\n\n/**\n * Created by bzai on 2018/4/11.\n * <p>\n * Desc:\n *\n *  预留用于继承渠道的Application\n */\n\npublic class ChannelApplication extends Application {\n\n    @Override\n    protected void attachBaseContext(Context base) {\n        super.attachBaseContext(base);\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/java/com/bzai/gamesdk/channel/lexiang/LexiangSDK.java",
    "content": "package com.bzai.gamesdk.channel.lexiang;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\n\nimport com.bzai.gamesdk.common.utils_base.config.TypeConfig;\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.parse.channel.Channel;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\nimport com.youxun.sdk.app.YouxunProxy;\nimport com.youxun.sdk.app.YouxunXF;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.HashMap;\n\n/**\n * @author bzai\n * @data 2018/9/11\n * <p>\n * Desc:乐享渠道SDK\n */\npublic class LexiangSDK extends Channel{\n\n    private final String TAG = getClass().getSimpleName();\n\n    private String game = \"tmj\";\n    private String key = \"4444b360a2c5b8d123f527a09c1f9f29\";\n\n    private CallBackListener channelAccountCallBackListener;\n    private CallBackListener purchaseCallBackListener;\n\n    @Override\n    protected void initChannel() {\n        LogUtils.d(TAG, getClass().getSimpleName() + \" has init\");\n    }\n\n    @Override\n    public String getChannelID() {\n        return null;\n    }\n\n    @Override\n    public boolean isSupport(int FuncType) {\n\n        switch (FuncType){\n\n            case TypeConfig.FUNC_SWITCHACCOUNT:\n                return false;\n\n            case TypeConfig.FUNC_LOGOUT:\n                return true;\n\n            case TypeConfig.FUNC_SHOW_FLOATWINDOW:\n                return false;\n\n            case TypeConfig.FUNC_DISMISS_FLOATWINDOW:\n                return false;\n\n            default:\n                return false;\n        }\n    }\n\n    @Override\n    public void init(Context context, HashMap<String, Object> initMap, CallBackListener initCallBackListener) {\n        LogUtils.d(TAG,getClass().getSimpleName() + \" init\");\n\n        //乐享SDK初始化\n        YouxunProxy.init(game,key);\n        initOnSuccess(initCallBackListener);\n    }\n\n    @Override\n    public void login(Context context, HashMap<String, Object> loginMap, CallBackListener loginCallBackListener) {\n        LogUtils.d(TAG,getClass().getSimpleName() + \" login\");\n\n        channelAccountCallBackListener = loginCallBackListener;\n        YouxunProxy.startLogin((Activity) context);\n    }\n\n    @Override\n    public void switchAccount(Context context, CallBackListener changeAccountCallBackLister) {\n        LogUtils.d(TAG,getClass().getSimpleName() + \" switchAccount\");\n    }\n\n    @Override\n    public void logout(Context context, CallBackListener logoutCallBackLister) {\n        LogUtils.d(TAG,getClass().getSimpleName() + \" logout\");\n\n        YouxunProxy.exitLogin((Activity) context);\n\n        YouxunXF.onDestroy();//销毁悬浮图标\n        logoutOnSuccess(channelAccountCallBackListener);\n    }\n\n    @Override\n    public void pay(Context context, HashMap<String, Object> payMap, CallBackListener payCallBackListener) {\n        LogUtils.d(TAG,getClass().getSimpleName() + \" pay\");\n\n        String productName = (String) payMap.get(\"productName\");\n        String orderId = (String) payMap.get(\"orderId\");\n        float price = convertToFloat(payMap.get(\"money\"),0) / 100;\n        String money = convertToString(price,\"\");\n        String serverID = (String) payMap.get(\"serverID\");\n\n        purchaseCallBackListener = payCallBackListener;\n        YouxunProxy.startPay((Activity) context, productName, money, orderId, serverID);\n    }\n\n    @Override\n    public void exit(Context context, CallBackListener exitCallBackLister) {\n        LogUtils.d(TAG,getClass().getSimpleName() + \" exit\");\n        channelNotExitDialog(exitCallBackLister);\n    }\n\n    @Override\n    public void onActivityResult(Context context, int requestCode, int resultCode, Intent data) {\n\n        if (requestCode == YouxunProxy.REQUEST_CODE_LOGIN && resultCode == YouxunProxy.RESULT_CODE_LOGIN){\n\n            //登录\n            loginCall(context, data);\n\n        }else \tif (requestCode == YouxunProxy.REQUEST_CODE_PAY && resultCode == YouxunProxy.RESULT_CODE_PAY) {\n\n            LogUtils.d(TAG,data.getStringExtra(\"data\"));\n\n            payOnComplete(purchaseCallBackListener);\n\n        }else if (requestCode == YouxunXF.REQUEST_CODE_SWITCH_ACCOUNT && resultCode == YouxunXF.RESULT_CODE_SWITCH_ACCOUNT){\n\n            //切换账号\n            YouxunXF.onDestroy();//销毁悬浮图标\n            login(context,null,channelAccountCallBackListener); //启动登录\n        }\n\n    }\n\n    @Override\n    public void onDestroy(Context context) {\n        YouxunXF.onDestroy();//销毁悬浮图标\n    }\n\n    private void loginCall(Context context, Intent data){\n\n        if (data.getStringExtra(\"data\").equals(\"success\")){\n\n            //登入成功\n            String userId = data.getStringExtra(\"userid\");\n            String msg = data.getStringExtra(\"msg\");\n            String time = data.getStringExtra(\"time\");\n            String sign = data.getStringExtra(\"sign\");\n            LogUtils.debug_d(TAG,\"userid=\" + userId + \"\\n\" +\n                    \"msg=\" + msg + \"\\n\" + \"time=\" + time + \"\\n\" + \"sign=\" + sign + \"\\n\");\n\n            //检测版本\n            YouxunProxy.updateDialog(context, data);\n\n            //提示用户账号信息\n            YouxunXF.hintUserInfo((Activity)context);\n\n            //创建悬浮图标\n            YouxunXF.onCreate((Activity)context,0.4f);\n\n            //将数据格式返回到上一层\n            JSONObject json = new JSONObject();\n            try {\n                json.put(\"sid\", userId);\n            } catch (JSONException e) {\n                e.printStackTrace();\n            }\n            loginOnSuccess(json.toString(),channelAccountCallBackListener);\n\n        }else {\n\n            //登录失败\n            loginOnFail(\"channel login fail\",channelAccountCallBackListener);\n        }\n    }\n\n\n    /**\n     * 转化为float\n     * @param value 传入对象\n     * @param defaultValue 发生异常时，返回默认值\n     * @return\n     */\n    public float convertToFloat(Object value, float defaultValue){\n\n        if (value == null || \"\".equals(value.toString().trim())){\n            return defaultValue;\n        }\n\n        try {\n            return Float.valueOf(value.toString());\n        }catch (Exception e){\n\n            try {\n                return Float.valueOf(String.valueOf(value));\n            }catch (Exception e1) {\n\n                try {\n                    return Long.valueOf(value.toString()).floatValue();\n                }catch (Exception e2){\n                    return defaultValue;\n                }\n            }\n        }\n    }\n\n    /**\n     * 转化为float\n     * @param value 传入对象\n     * @param defaultValue 发生异常时，返回默认值\n     * @return\n     */\n    public String convertToString(Object value, String defaultValue){\n\n        if (value == null || \"\".equals(value.toString().trim())){\n            return defaultValue;\n        }\n\n        //普通数据类型先转化\n        try {\n            return String.valueOf(value);\n        }catch (Exception e){\n\n            try {\n                return value.toString();\n            }catch (Exception e1) {\n                return defaultValue;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/drawable/youxun_border_stroke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <item>\n        <shape>\n            <stroke\n                android:dashGap=\"2dp\"\n                android:dashWidth=\"2dp\"\n                android:width=\"1dp\"\n                android:color=\"#40b5ef\" />\n\n            <solid android:color=\"#FFFFFF\" />\n\n            <corners android:radius=\"0dp\" />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/drawable/youxun_cir_hint_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n\n    <item android:state_pressed=\"false\"><shape>\n            <solid android:color=\"#99ffffff\" />\n\n            <corners android:bottomLeftRadius=\"2dip\" android:bottomRightRadius=\"2dip\" android:topLeftRadius=\"2dip\" android:topRightRadius=\"2dip\" />\n        </shape></item>\n\n</selector>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/drawable/youxun_cir_rect.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:state_pressed=\"true\"><shape>\n            <solid android:color=\"#fd8111\" />\n\n            <corners android:bottomLeftRadius=\"2dip\" android:bottomRightRadius=\"2dip\" android:topLeftRadius=\"2dip\" android:topRightRadius=\"2dip\" />\n        </shape></item>\n    <item android:state_pressed=\"false\"><shape>\n            <solid android:color=\"#fd9538\" />\n\n            <corners android:bottomLeftRadius=\"2dip\" android:bottomRightRadius=\"2dip\" android:topLeftRadius=\"2dip\" android:topRightRadius=\"2dip\" />\n        </shape></item>\n\n</selector>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/drawable/youxun_drawable_1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:state_pressed=\"false\" android:state_enabled=\"true\">\n        <shape>\n            <solid android:color=\"#ff606d\" />\n\n            <corners android:bottomLeftRadius=\"3dip\" android:bottomRightRadius=\"3dip\" android:topLeftRadius=\"3dip\" android:topRightRadius=\"3dip\" />\n        </shape>\n    </item>\n        \n    <item android:state_pressed=\"true\" android:state_enabled=\"true\">\n        <shape>\n            <solid android:color=\"#ff4a58\" />\n            \n            <corners android:bottomLeftRadius=\"3dip\" android:bottomRightRadius=\"3dip\" android:topLeftRadius=\"3dip\" android:topRightRadius=\"3dip\" />\n        </shape>\n    </item>\n    \n    <item android:state_enabled=\"false\">\n        <shape>\n            <solid android:color=\"#ff858f\" />\n            \n            <corners android:bottomLeftRadius=\"3dip\" android:bottomRightRadius=\"3dip\" android:topLeftRadius=\"3dip\" android:topRightRadius=\"3dip\" />\n        </shape>\n    </item>\n\n</selector>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/drawable/youxun_drawable_2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:state_pressed=\"false\"><shape>\n            <solid android:color=\"#00000000\" />\n\n            <stroke android:width=\"1dp\" android:color=\"#c6c6c6\"></stroke>\n\n            <corners android:radius=\"3dp\" />\n        </shape></item>\n\n</selector>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/drawable/youxun_drawable_3.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:state_pressed=\"false\"><shape>\n            <solid android:color=\"#00000000\" />\n\n            <stroke android:width=\"1dp\" android:color=\"#c6c6c6\" />\n\n            <corners android:bottomLeftRadius=\"3dip\" android:topLeftRadius=\"3dip\" />\n        </shape></item>\n\n</selector>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/drawable/youxun_drawable_33.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:state_pressed=\"false\"><shape>\n            <solid android:color=\"#ff606d\" />\n\n            <corners android:bottomLeftRadius=\"3dip\" android:topLeftRadius=\"3dip\" />\n        </shape></item>\n\n</selector>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/drawable/youxun_drawable_4.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:state_pressed=\"false\"><shape>\n            <solid android:color=\"#00000000\" />\n\n            <stroke android:width=\"1dp\" android:color=\"#c6c6c6\" />\n\n            <corners android:bottomRightRadius=\"3dip\" android:topRightRadius=\"3dip\" />\n        </shape></item>\n\n</selector>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/drawable/youxun_drawable_44.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:state_pressed=\"false\"><shape>\n            <solid android:color=\"#ff606d\" />\n\n            <corners android:bottomRightRadius=\"3dip\" android:topRightRadius=\"3dip\" />\n        </shape></item>\n\n</selector>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/drawable/youxun_drawable_5.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@drawable/youxun_login_11\" android:state_checked=\"true\" android:state_enabled=\"true\"/>\n    <item android:drawable=\"@drawable/youxun_login_12\" android:state_checked=\"false\" android:state_enabled=\"true\"/>\n\n</selector>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/drawable/youxun_drawable_6.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:state_pressed=\"false\">\n        <shape>\n            <solid android:color=\"#ffffff\" />\n\n            <stroke android:width=\"1dp\" android:color=\"#c6c6c6\"></stroke>\n        </shape>\n\t</item>\n\n</selector>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/drawable/youxun_service_rect.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:state_pressed=\"false\"><shape>\n            <solid android:color=\"#fff2e4\" />\n\n            <stroke android:width=\"1px\" android:color=\"#fc9439\"></stroke>\n\n            <corners android:radius=\"0dp\" />\n        </shape></item>\n\n</selector>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_account.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\" >\n\n    <include layout=\"@layout/youxun_account_login\" />\n\n    <include layout=\"@layout/youxun_account_reg\" />\n\n</FrameLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_account_hint.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\" >\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"40dp\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginTop=\"10dp\"\n        android:background=\"@drawable/youxun_cir_hint_bg\"\n        android:gravity=\"center\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"20dp\"\n        android:paddingRight=\"20dp\" >\n\n        <ImageView\n            android:layout_width=\"25dp\"\n            android:layout_height=\"25dp\"\n            android:contentDescription=\"@null\"\n            android:src=\"@drawable/youxun_acchint_logo\" />\n\n        <TextView\n            android:id=\"@+id/youxun_account_hint_tv\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"10dp\"\n            android:singleLine=\"true\"\n            android:textColor=\"#000000\"\n            android:textSize=\"12sp\" />\n    </LinearLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_account_login.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/youxun_account_login_rl\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\"\n    android:visibility=\"gone\" >\n\n    <RelativeLayout\n        android:layout_width=\"402dp\"\n        android:layout_height=\"216dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@drawable/youxun_login_1\" >\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\" >\n\n            <ImageView\n                android:layout_width=\"116dp\"\n                android:layout_height=\"140dp\"\n                android:layout_marginTop=\"12.5dp\"\n                android:padding=\"16dp\"\n                android:src=\"@drawable/youxun_login_8\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginRight=\"10dp\"\n                android:orientation=\"vertical\" >\n\n                <RelativeLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"10dp\"\n                    android:background=\"@drawable/youxun_drawable_2\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_6\" />\n\n                    <EditText\n                        android:id=\"@+id/youxun_account_login_acc\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginLeft=\"40dip\"\n                        android:layout_marginRight=\"35dip\"\n                        android:background=\"@null\"\n                        android:hint=\"请输入用户名\"\n                        android:imeOptions=\"flagNoExtractUi\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textColorHint=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <ImageView\n                        android:id=\"@+id/youxun_account_login_acc_close\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:padding=\"10dp\"\n                        android:src=\"@drawable/youxun_login_9\"\n                        android:visibility=\"gone\" />\n                </RelativeLayout>\n\n                <RelativeLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"5dp\"\n                    android:background=\"@drawable/youxun_drawable_2\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_7\" />\n\n                    <EditText\n                        android:id=\"@+id/youxun_account_login_pass\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginLeft=\"40dip\"\n                        android:layout_marginRight=\"35dp\"\n                        android:background=\"@null\"\n                        android:hint=\"请输入密码\"\n                        android:imeOptions=\"flagNoExtractUi\"\n                        android:inputType=\"textPassword\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textColorHint=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <ImageView\n                        android:id=\"@+id/youxun_account_login_pass_close\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:padding=\"10dp\"\n                        android:src=\"@drawable/youxun_login_9\"\n                        android:visibility=\"gone\" />\n                </RelativeLayout>\n\n                <Button\n                    android:id=\"@+id/youxun_account_login_btn\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"5dp\"\n                    android:background=\"@drawable/youxun_drawable_1\"\n                    android:enabled=\"false\"\n                    android:text=\"登录\"\n                    android:textColor=\"#ffffff\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_marginBottom=\"50dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginRight=\"10dp\"\n            android:background=\"#c6c6c6\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"50dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:orientation=\"horizontal\" >\n\n            <LinearLayout\n                android:id=\"@+id/youxun_account_login_forget\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1.0\"\n                android:gravity=\"center\"\n                android:orientation=\"horizontal\" >\n\n                <ImageView\n                    android:layout_width=\"20dp\"\n                    android:layout_height=\"20dp\"\n                    android:src=\"@drawable/youxun_login_7\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginLeft=\"5dp\"\n                    android:text=\"忘记密码>\"\n                    android:textColor=\"#919191\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n\n            <LinearLayout\n                android:id=\"@+id/youxun_account_login_reg\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1.0\"\n                android:gravity=\"center\"\n                android:orientation=\"horizontal\" >\n\n                <ImageView\n                    android:layout_width=\"20dp\"\n                    android:layout_height=\"20dp\"\n                    android:src=\"@drawable/youxun_login_6\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginLeft=\"5dp\"\n                    android:text=\"账号注册>\"\n                    android:textColor=\"#919191\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <ImageButton\n            android:id=\"@+id/youxun_account_login_back\"\n            android:layout_width=\"25dp\"\n            android:layout_height=\"25dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginTop=\"10dp\"\n            android:background=\"@null\"\n            android:src=\"@drawable/youxun_login_5\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_account_reg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/youxun_account_reg_rl\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\"\n    android:visibility=\"gone\" >\n\n    <RelativeLayout\n        android:layout_width=\"402dp\"\n        android:layout_height=\"216dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@drawable/youxun_login_1\" >\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\" >\n\n            <ImageView\n                android:layout_width=\"116dp\"\n                android:layout_height=\"140dp\"\n                android:layout_marginTop=\"12.5dp\"\n                android:padding=\"16dp\"\n                android:src=\"@drawable/youxun_login_8\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginRight=\"10dp\"\n                android:orientation=\"vertical\" >\n\n                <RelativeLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"10dp\"\n                    android:background=\"@drawable/youxun_drawable_2\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_6\" />\n\n                    <EditText\n                        android:id=\"@+id/youxun_account_reg_acc\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginLeft=\"40dip\"\n                        android:layout_marginRight=\"35dip\"\n                        android:background=\"@null\"\n                        android:hint=\"请输入用户名\"\n                        android:imeOptions=\"flagNoExtractUi\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textColorHint=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <ImageView\n                        android:id=\"@+id/youxun_account_reg_acc_close\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:padding=\"10dp\"\n                        android:src=\"@drawable/youxun_login_9\"\n                        android:visibility=\"gone\" />\n                </RelativeLayout>\n\n                <RelativeLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"5dp\"\n                    android:background=\"@drawable/youxun_drawable_2\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_7\" />\n\n                    <EditText\n                        android:id=\"@+id/youxun_account_reg_pass1\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginLeft=\"40dip\"\n                        android:layout_marginRight=\"35dp\"\n                        android:background=\"@null\"\n                        android:hint=\"请输入密码\"\n                        android:imeOptions=\"flagNoExtractUi\"\n                        android:inputType=\"textPassword\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textColorHint=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <ImageView\n                        android:id=\"@+id/youxun_account_reg_pass_close1\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:padding=\"10dp\"\n                        android:src=\"@drawable/youxun_login_9\"\n                        android:visibility=\"gone\" />\n                </RelativeLayout>\n\n                <RelativeLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"5dp\"\n                    android:background=\"@drawable/youxun_drawable_2\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_7\" />\n\n                    <EditText\n                        android:id=\"@+id/youxun_account_reg_pass2\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginLeft=\"40dip\"\n                        android:layout_marginRight=\"35dp\"\n                        android:background=\"@null\"\n                        android:hint=\"确认密码\"\n                        android:imeOptions=\"flagNoExtractUi\"\n                        android:inputType=\"textPassword\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textColorHint=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <ImageView\n                        android:id=\"@+id/youxun_account_reg_pass_close2\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:padding=\"10dp\"\n                        android:src=\"@drawable/youxun_login_9\"\n                        android:visibility=\"gone\" />\n                </RelativeLayout>\n\n                <Button\n                    android:id=\"@+id/youxun_account_reg_btn\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"5dp\"\n                    android:background=\"@drawable/youxun_drawable_1\"\n                    android:enabled=\"false\"\n                    android:text=\"注册并登录\"\n                    android:textColor=\"#ffffff\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <ImageButton\n            android:id=\"@+id/youxun_account_reg_back\"\n            android:layout_width=\"25dp\"\n            android:layout_height=\"25dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginTop=\"10dp\"\n            android:background=\"@null\"\n            android:src=\"@drawable/youxun_login_5\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_bound.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/youxun_bound_rl\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\" >\n\n    <RelativeLayout\n        android:id=\"@+id/youxun_bound_phone_rl\"\n        android:layout_width=\"402dp\"\n        android:layout_height=\"165dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@drawable/youxun_login_1\"\n        android:visibility=\"gone\" >\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\" >\n\n            <ImageView\n                android:layout_width=\"116dp\"\n                android:layout_height=\"140dp\"\n                android:layout_marginTop=\"12.5dp\"\n                android:padding=\"16dp\"\n                android:src=\"@drawable/youxun_login_8\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginRight=\"10dp\"\n                android:orientation=\"vertical\" >\n\n                <RelativeLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"10dp\"\n                    android:background=\"@drawable/youxun_drawable_2\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_6\" />\n\n                    <EditText\n                        android:id=\"@+id/youxun_bound_acc_et\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginLeft=\"40dip\"\n                        android:layout_marginRight=\"35dip\"\n                        android:background=\"@null\"\n                        android:hint=\"请输入手机号\"\n                        android:imeOptions=\"flagNoExtractUi\"\n                        android:inputType=\"number\"\n                        android:maxLength=\"13\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textColorHint=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <ImageView\n                        android:id=\"@+id/youxun_bound_acc_close\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:padding=\"10dp\"\n                        android:src=\"@drawable/youxun_login_9\"\n                        android:visibility=\"gone\" />\n                </RelativeLayout>\n\n                <RelativeLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"2dp\"\n                    android:background=\"@drawable/youxun_drawable_2\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_10\" />\n\n                    <EditText\n                        android:id=\"@+id/youxun_bound_code_et\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginLeft=\"40dip\"\n                        android:layout_marginRight=\"81dp\"\n                        android:background=\"@null\"\n                        android:hint=\"请输入短信验证码\"\n                        android:imeOptions=\"flagNoExtractUi\"\n                        android:inputType=\"number\"\n                        android:maxLength=\"4\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textColorHint=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <View\n                        android:layout_width=\"1dp\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_marginBottom=\"10dp\"\n                        android:layout_marginRight=\"80dp\"\n                        android:layout_marginTop=\"10dp\"\n                        android:background=\"#c6c6c6\" />\n\n                    <Button\n                        android:id=\"@+id/youxun_bound_code_btn\"\n                        android:layout_width=\"80dp\"\n                        android:layout_height=\"45dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:background=\"@null\"\n                        android:text=\"获取验证码\"\n                        android:textColor=\"#ff606d\"\n                        android:textSize=\"14sp\" />\n                </RelativeLayout>\n\n                <Button\n                    android:id=\"@+id/youxun_bound_btn\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"5dp\"\n                    android:background=\"@drawable/youxun_drawable_1\"\n                    android:enabled=\"false\"\n                    android:text=\"绑定\"\n                    android:textColor=\"#ffffff\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <ImageButton\n            android:id=\"@+id/youxun_bound_back\"\n            android:layout_width=\"25dp\"\n            android:layout_height=\"25dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginTop=\"10dp\"\n            android:background=\"@null\"\n            android:src=\"@drawable/youxun_login_5\" />\n    </RelativeLayout>\n\n    <RelativeLayout\n        android:id=\"@+id/youxun_bound_card_rl\"\n        android:layout_width=\"402dp\"\n        android:layout_height=\"165dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@drawable/youxun_login_1\"\n        android:visibility=\"gone\" >\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\" >\n\n            <ImageView\n                android:layout_width=\"116dp\"\n                android:layout_height=\"140dp\"\n                android:layout_marginTop=\"12.5dp\"\n                android:padding=\"16dp\"\n                android:src=\"@drawable/youxun_login_8\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginRight=\"10dp\"\n                android:orientation=\"vertical\" >\n\n                <RelativeLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"10dp\"\n                    android:background=\"@drawable/youxun_drawable_2\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_6\" />\n\n                    <EditText\n                        android:id=\"@+id/youxun_card_name_et\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginLeft=\"40dip\"\n                        android:layout_marginRight=\"35dip\"\n                        android:background=\"@null\"\n                        android:hint=\"请输入真实姓名\"\n                        android:imeOptions=\"flagNoExtractUi\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textColorHint=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <ImageView\n                        android:id=\"@+id/youxun_card_name_close\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:padding=\"10dp\"\n                        android:src=\"@drawable/youxun_login_9\"\n                        android:visibility=\"gone\" />\n                </RelativeLayout>\n\n                <RelativeLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"2dp\"\n                    android:background=\"@drawable/youxun_drawable_2\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_10\" />\n\n                    <EditText\n                        android:id=\"@+id/youxun_card_c_et\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginLeft=\"40dip\"\n                        android:layout_marginRight=\"35dp\"\n                        android:background=\"@null\"\n                        android:hint=\"请输入身份证号码\"\n                        android:imeOptions=\"flagNoExtractUi\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textColorHint=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <ImageView\n                        android:id=\"@+id/youxun_card_c_close\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:padding=\"10dp\"\n                        android:src=\"@drawable/youxun_login_9\"\n                        android:visibility=\"gone\" />\n                </RelativeLayout>\n\n                <Button\n                    android:id=\"@+id/youxun_card_btn\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"5dp\"\n                    android:background=\"@drawable/youxun_drawable_1\"\n                    android:enabled=\"false\"\n                    android:text=\"绑定\"\n                    android:textColor=\"#ffffff\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <ImageButton\n            android:id=\"@+id/youxun_card_back\"\n            android:layout_width=\"25dp\"\n            android:layout_height=\"25dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginTop=\"10dp\"\n            android:background=\"@null\"\n            android:src=\"@drawable/youxun_login_5\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\" >\n\n    <RelativeLayout\n        android:layout_width=\"241dp\"\n        android:layout_height=\"129dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@drawable/youxun_login_1\" >\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_marginTop=\"10dp\"\n            android:text=\"提示\"\n            android:textColor=\"#000000\"\n            android:textSize=\"14sp\"\n            android:textStyle=\"bold\" />\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginTop=\"38dp\"\n            android:text=\"将创建游客账号以便快速登录，建议进入游戏后尽快绑定一个账号！\"\n            android:textColor=\"#666666\"\n            android:textSize=\"14sp\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"40dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:orientation=\"horizontal\" >\n\n            <Button\n                android:id=\"@+id/youxun_dialog_btn1\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1.0\"\n                android:background=\"@null\"\n                android:text=\"账号登录\"\n                android:textColor=\"#3ab970\"\n                android:textSize=\"14sp\" />\n\n            <Button\n                android:id=\"@+id/youxun_dialog_btn2\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1.0\"\n                android:background=\"@null\"\n                android:text=\"快速游戏\"\n                android:textColor=\"#3ab970\"\n                android:textSize=\"14sp\" />\n        </LinearLayout>\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_marginBottom=\"40dp\"\n            android:background=\"#c1c1c2\" />\n\n        <View\n            android:layout_width=\"1dp\"\n            android:layout_height=\"40dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_centerHorizontal=\"true\"\n            android:background=\"#c1c1c2\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_dialog2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\" >\n\n    <RelativeLayout\n        android:layout_width=\"241dp\"\n        android:layout_height=\"139dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@drawable/youxun_login_1\" >\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_marginTop=\"10dp\"\n            android:text=\"提示\"\n            android:textColor=\"#000000\"\n            android:textSize=\"14sp\"\n            android:textStyle=\"bold\" />\n\n        <TextView\n            android:id=\"@+id/youxun_dialog2_tv\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginTop=\"38dp\"\n            android:textColor=\"#666666\"\n            android:textSize=\"14sp\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"40dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:orientation=\"horizontal\" >\n\n            <Button\n                android:id=\"@+id/youxun_dialog2_btn1\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1.0\"\n                android:background=\"@null\"\n                android:text=\"下次再说\"\n                android:textColor=\"#3ab970\"\n                android:textSize=\"14sp\" />\n\n            <Button\n                android:id=\"@+id/youxun_dialog2_btn2\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1.0\"\n                android:background=\"@null\"\n                android:text=\"马上绑定\"\n                android:textColor=\"#3ab970\"\n                android:textSize=\"14sp\" />\n        </LinearLayout>\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_marginBottom=\"40dp\"\n            android:background=\"#c1c1c2\" />\n\n        <View\n            android:layout_width=\"1dp\"\n            android:layout_height=\"40dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_centerHorizontal=\"true\"\n            android:background=\"#c1c1c2\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_dialog3.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\" >\n\n    <RelativeLayout\n        android:layout_width=\"241dp\"\n        android:layout_height=\"139dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@drawable/youxun_login_1\" >\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_marginTop=\"10dp\"\n            android:text=\"提示\"\n            android:textColor=\"#000000\"\n            android:textSize=\"14sp\"\n            android:textStyle=\"bold\" />\n\n        <TextView\n            android:id=\"@+id/youxun_dialog3_tv\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginTop=\"38dp\"\n            android:textColor=\"#666666\"\n            android:textSize=\"14sp\" />\n\n        <Button\n            android:id=\"@+id/youxun_dialog3_bind\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"40dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:background=\"@null\"\n            android:text=\"马上绑定\"\n            android:textColor=\"#3ab970\"\n            android:textSize=\"14sp\" />\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_marginBottom=\"40dp\"\n            android:background=\"#c1c1c2\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_floating.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\" >\n\n    <ImageView\n        android:id=\"@+id/youxun_f_iv\"\n        android:layout_width=\"50dp\"\n        android:layout_height=\"50dp\"\n        android:background=\"@drawable/youxun_float_icon_gb\"\n        android:contentDescription=\"@null\" />\n\n</LinearLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_gb_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" >\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"#99000000\" >\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dp\"\n            android:layout_marginRight=\"60dp\"\n            android:layout_marginTop=\"50dp\"\n            android:background=\"@android:color/white\"\n            android:orientation=\"vertical\" >\n\n            <ImageView\n                android:id=\"@+id/youxun_dia_close\"\n                android:layout_width=\"30dp\"\n                android:layout_height=\"30dp\"\n                android:layout_gravity=\"right\"\n                android:contentDescription=\"@null\"\n                android:padding=\"6dp\"\n                android:src=\"@drawable/youxun_close\" />\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"10dp\"\n                android:text=\"礼包内容：\"\n                android:textColor=\"#333333\"\n                android:textSize=\"14sp\" />\n\n            <TextView\n                android:id=\"@+id/youxun_gb_dia_info\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"10dp\"\n                android:lineSpacingMultiplier=\"1.2\"\n                android:textColor=\"#666666\"\n                android:textSize=\"14sp\" />\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"10dp\"\n                android:text=\"兑换方式：\"\n                android:textColor=\"#333333\"\n                android:textSize=\"14sp\" />\n\n            <TextView\n                android:id=\"@+id/youxun_gb_dia_methods\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"10dp\"\n                android:lineSpacingMultiplier=\"1.2\"\n                android:textColor=\"#666666\"\n                android:textSize=\"14sp\" />\n\n            <TextView\n                android:id=\"@+id/youxun_gb_dia_number\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginLeft=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:background=\"@drawable/youxun_border_stroke\"\n                android:gravity=\"center\"\n                android:padding=\"10dp\"\n                android:textColor=\"#333333\"\n                android:textSize=\"18sp\" />\n\n            <Button\n                android:id=\"@+id/youxun_gb_dia_copy\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"40dp\"\n                android:layout_marginTop=\"10dp\"\n                android:background=\"#6ac13e\"\n                android:text=\"复制兑换码\"\n                android:textColor=\"@android:color/white\"\n                android:textSize=\"14sp\" />\n        </LinearLayout>\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_gb_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\" >\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"5dp\"\n        android:layout_marginRight=\"5dp\"\n        android:layout_marginTop=\"1.5px\"\n        android:background=\"#efefef\"\n        android:orientation=\"vertical\" >\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dp\"\n            android:layout_marginRight=\"5dp\"\n            android:layout_marginTop=\"10dp\" >\n\n            <ImageView\n                android:id=\"@+id/youxun_gb_item_icon\"\n                android:layout_width=\"40dp\"\n                android:layout_height=\"40dp\"\n                android:contentDescription=\"@null\" />\n\n            <TextView\n                android:id=\"@+id/youxun_gb_item_title\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"45dp\"\n                android:layout_marginTop=\"5dp\"\n                android:textColor=\"#666666\"\n                android:textSize=\"14sp\" />\n\n            <Button\n                android:id=\"@+id/youxun_gb_item_get\"\n                android:layout_width=\"50dp\"\n                android:layout_height=\"25dp\"\n                android:layout_alignParentRight=\"true\"\n                android:layout_centerVertical=\"true\"\n                android:background=\"@drawable/youxun_cir_rect\"\n                android:text=\"领取 \"\n                android:textColor=\"@android:color/white\"\n                android:textSize=\"14sp\" />\n        </RelativeLayout>\n\n        <TextView\n            android:id=\"@+id/youxun_gb_item_info\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"10dp\"\n            android:layout_marginLeft=\"5dp\"\n            android:layout_marginRight=\"5dp\"\n            android:layout_marginTop=\"5dp\"\n            android:textColor=\"#999999\"\n            android:textSize=\"12sp\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_gb_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"#efefef\"\n    android:orientation=\"vertical\" >\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"5dp\"\n        android:layout_marginTop=\"5dp\"\n        android:background=\"@android:color/white\"\n        android:orientation=\"horizontal\" >\n\n        <LinearLayout\n            android:id=\"@+id/youxun_share_ll\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"10dp\"\n            android:layout_marginTop=\"10dp\"\n            android:layout_weight=\"1.0\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\" >\n\n            <ImageView\n                android:layout_width=\"35dp\"\n                android:layout_height=\"35dp\"\n                android:contentDescription=\"@null\"\n                android:src=\"@drawable/youxun_share\" />\n\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"5dp\"\n                android:gravity=\"center\"\n                android:text=\"官网\"\n                android:textColor=\"#666666\"\n                android:textSize=\"14sp\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/youxun_attent_ll\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"10dp\"\n            android:layout_marginTop=\"10dp\"\n            android:layout_weight=\"1.0\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\" >\n\n            <ImageView\n                android:layout_width=\"35dp\"\n                android:layout_height=\"35dp\"\n                android:contentDescription=\"@null\"\n                android:src=\"@drawable/youxun_attent\" />\n\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"5dp\"\n                android:gravity=\"center\"\n                android:text=\"关注\"\n                android:textColor=\"#666666\"\n                android:textSize=\"14sp\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/youxun_g_ll\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"10dp\"\n            android:layout_marginTop=\"10dp\"\n            android:layout_weight=\"1.0\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\" >\n\n            <ImageView\n                android:layout_width=\"35dp\"\n                android:layout_height=\"35dp\"\n                android:contentDescription=\"@null\"\n                android:src=\"@drawable/youxun_gb\" />\n\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"5dp\"\n                android:gravity=\"center\"\n                android:text=\"礼包\"\n                android:textColor=\"#666666\"\n                android:textSize=\"14sp\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/youxun_ser_ll\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"10dp\"\n            android:layout_marginTop=\"10dp\"\n            android:layout_weight=\"1.0\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\" >\n\n            <ImageView\n                android:layout_width=\"35dp\"\n                android:layout_height=\"35dp\"\n                android:contentDescription=\"@null\"\n                android:src=\"@drawable/youxun_service_icon\" />\n\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"5dp\"\n                android:gravity=\"center\"\n                android:text=\"客服\"\n                android:textColor=\"#666666\"\n                android:textSize=\"14sp\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/youxun_sa_ll\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"10dp\"\n            android:layout_marginTop=\"10dp\"\n            android:layout_weight=\"1.0\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\" >\n\n            <ImageView\n                android:layout_width=\"35dp\"\n                android:layout_height=\"35dp\"\n                android:contentDescription=\"@null\"\n                android:src=\"@drawable/youxun_switch_account\" />\n\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"5dp\"\n                android:gravity=\"center\"\n                android:text=\"用户中心\"\n                android:textColor=\"#666666\"\n                android:textSize=\"14sp\" />\n        </LinearLayout>\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_gift_bag.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"#99000000\" >\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginRight=\"55dp\"\n        android:background=\"@android:color/white\"\n        android:orientation=\"vertical\" >\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"50dp\" >\n\n            <ImageView\n                android:layout_width=\"90dp\"\n                android:layout_height=\"21dp\"\n                android:layout_centerInParent=\"true\"\n                android:src=\"@drawable/youxun_float_logo\" />\n        </RelativeLayout>\n\n        <include layout=\"@layout/youxun_gb_menu\" />\n\n        <include layout=\"@layout/youxun_menu_2\" />\n\n        <include layout=\"@layout/youxun_menu_3\" />\n\n        <include layout=\"@layout/youxun_menu_4\" />\n    </LinearLayout>\n\n    <RelativeLayout\n        android:id=\"@+id/youxun_gb_rl\"\n        android:layout_width=\"55dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentRight=\"true\" >\n\n        <ImageView\n            android:id=\"@+id/youxun_gb_iv\"\n            android:layout_width=\"23dp\"\n            android:layout_height=\"65dp\"\n            android:layout_centerVertical=\"true\"\n            android:contentDescription=\"@null\"\n            android:src=\"@drawable/youxun_float_left_arrow\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_login.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    android:id=\"@+id/youxun_login_fl\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"match_parent\"\r\n    android:background=\"#99000000\"\r\n    android:visibility=\"gone\" >\r\n\r\n    <include layout=\"@layout/youxun_login_menu\" />\r\n\r    <include layout=\"@layout/youxun_login_footprint\" />\r\n\r\n</FrameLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_login_footprint.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/youxun_login_footprint_rl\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\"\n    android:visibility=\"gone\" >\n\n    <RelativeLayout\n        android:layout_width=\"402dp\"\n        android:layout_height=\"216dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@drawable/youxun_login_1\" >\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\" >\n\n            <ImageView\n                android:layout_width=\"116dp\"\n                android:layout_height=\"140dp\"\n                android:layout_marginTop=\"12.5dp\"\n                android:padding=\"16dp\"\n                android:src=\"@drawable/youxun_login_8\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginRight=\"10dp\"\n                android:orientation=\"vertical\" >\n\n                <RelativeLayout\n                    android:id=\"@+id/youxun_login_footprint_rl_\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"25dp\"\n                    android:background=\"@drawable/youxun_drawable_2\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_13\" />\n\n                    <TextView\n                        android:id=\"@+id/youxun_login_footprint_tv\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"40dip\"\n                        android:layout_marginRight=\"35dip\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textSize=\"14sp\" />\n\n                    <ImageView\n                        android:id=\"@+id/youxun_login_footprint_open\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:padding=\"10dp\"\n                        android:src=\"@drawable/youxun_login_14\" />\n                </RelativeLayout>\n\n                <Button\n                    android:id=\"@+id/youxun_login_footprint_btn\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"25dp\"\n                    android:background=\"@drawable/youxun_drawable_1\"\n                    android:text=\"登录\"\n                    android:textColor=\"#ffffff\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_marginBottom=\"50dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginRight=\"10dp\"\n            android:background=\"#c6c6c6\" />\n\n        <RelativeLayout\n            android:id=\"@+id/youxun_login_footprint_more\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"50dp\"\n            android:layout_alignParentBottom=\"true\" >\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_centerInParent=\"true\"\n                android:text=\"使用其他账号登录>\"\n                android:textColor=\"#ff606d\"\n                android:textSize=\"14sp\" />\n        </RelativeLayout>\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_login_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/youxun_login_menu_rl\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\"\n    android:visibility=\"gone\" >\n\n    <LinearLayout\n        android:layout_width=\"402dp\"\n        android:layout_height=\"216dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@drawable/youxun_login_1\"\n        android:orientation=\"vertical\" >\n\n        <ImageView\n            android:layout_width=\"150dp\"\n            android:layout_height=\"35.5dp\"\n            android:layout_gravity=\"center\"\n            android:layout_marginTop=\"10dp\"\n            android:src=\"@drawable/youxun_float_logo\" />\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_marginTop=\"5dp\"\n            android:text=\"选择登录方式\"\n            android:textColor=\"#474747\"\n            android:textSize=\"16sp\" />\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" >\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_centerInParent=\"true\"\n                android:layout_marginLeft=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:orientation=\"horizontal\" >\n\n                <LinearLayout\n                    android:id=\"@+id/youxun_login_menu_ll1\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1.0\"\n                    android:gravity=\"center\"\n                    android:orientation=\"vertical\" >\n\n                    <ImageView\n                        android:layout_width=\"75dp\"\n                        android:layout_height=\"75dp\"\n                        android:src=\"@drawable/youxun_login_2\" />\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginTop=\"5dp\"\n                        android:text=\"快速游戏\"\n                        android:textColor=\"#474747\"\n                        android:textSize=\"14sp\" />\n                </LinearLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/youxun_login_menu_ll2\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1.0\"\n                    android:gravity=\"center\"\n                    android:orientation=\"vertical\" >\n\n                    <ImageView\n                        android:layout_width=\"75dp\"\n                        android:layout_height=\"75dp\"\n                        android:src=\"@drawable/youxun_login_3\" />\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginTop=\"5dp\"\n                        android:text=\"手机登录\"\n                        android:textColor=\"#474747\"\n                        android:textSize=\"14sp\" />\n                </LinearLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/youxun_login_menu_ll3\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1.0\"\n                    android:gravity=\"center\"\n                    android:orientation=\"vertical\" >\n\n                    <ImageView\n                        android:layout_width=\"75dp\"\n                        android:layout_height=\"75dp\"\n                        android:src=\"@drawable/youxun_login_4\" />\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginTop=\"5dp\"\n                        android:text=\"账号登录\"\n                        android:textColor=\"#474747\"\n                        android:textSize=\"14sp\" />\n                </LinearLayout>\n            </LinearLayout>\n        </RelativeLayout>\n    </LinearLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_login_option_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\" >\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"45dp\"\n        android:background=\"#ffffff\" >\n\n        <ImageView\n            android:layout_width=\"20dp\"\n            android:layout_height=\"20dp\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginLeft=\"10dp\"\n            android:src=\"@drawable/youxun_login_13\" />\n\n        <TextView\n            android:id=\"@+id/youxun_login_oi_tv\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginLeft=\"40dip\"\n            android:layout_marginRight=\"35dip\"\n            android:gravity=\"center_vertical\"\n            android:singleLine=\"true\"\n            android:textColor=\"#474747\"\n            android:textSize=\"14sp\" />\n\n        <ImageView\n            android:id=\"@+id/youxun_login_oi_ib\"\n            android:layout_width=\"35dp\"\n            android:layout_height=\"35dp\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:padding=\"10dp\"\n            android:src=\"@drawable/youxun_login_9\" />\n    </RelativeLayout>\n\n</LinearLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_login_popup.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\" >\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"137dp\"\n        android:background=\"@drawable/youxun_drawable_6\"\n        android:orientation=\"vertical\"\n        android:padding=\"1dp\" >\n\n        <ListView\n            android:id=\"@+id/youxun_login_po_lv\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"@null\"\n            android:cacheColorHint=\"@null\"\n            android:divider=\"#c6c6c6\"\n            android:dividerHeight=\"1dp\"\n            android:fadingEdge=\"none\"\n            android:fastScrollEnabled=\"false\"\n            android:footerDividersEnabled=\"false\"\n            android:headerDividersEnabled=\"false\"\n            android:scrollbars=\"none\"\n            android:smoothScrollbar=\"true\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_menu_2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/youxun_menu_2_ll\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:visibility=\"gone\" >\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@android:color/white\"\n        android:orientation=\"vertical\" >\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"40dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:gravity=\"center_vertical\"\n            android:text=\"关注我们\"\n            android:textColor=\"#666666\"\n            android:textSize=\"16sp\" />\n\n        <ScrollView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" >\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"5dp\"\n                android:layout_marginRight=\"5dp\"\n                android:background=\"#efefef\"\n                android:gravity=\"center_horizontal\"\n                android:orientation=\"vertical\"\n                android:padding=\"10dp\" >\n\n                <ImageView\n                    android:layout_width=\"154dp\"\n                    android:layout_height=\"154dp\"\n                    android:contentDescription=\"@null\"\n                    android:src=\"@drawable/youxun_code\" />\n\n                <TextView\n                    android:id=\"@+id/youxun_menu_2_tv\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"10dp\"\n                    android:gravity=\"center_vertical\"\n                    android:text=\"搜索微信公众号“悠迅微游”可获得最新游戏咨询及礼包，赶快来关注吧！\"\n                    android:textColor=\"#999999\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n        </ScrollView>\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_menu_3.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/youxun_menu_3_ll\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:visibility=\"gone\" >\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@android:color/white\"\n        android:orientation=\"vertical\" >\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"40dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:gravity=\"center_vertical\"\n            android:text=\"礼包\"\n            android:textColor=\"#666666\"\n            android:textSize=\"16sp\" />\n\n        <TextView\n            android:id=\"@+id/youxun_gb_hint_tv\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"30dp\"\n            android:layout_marginLeft=\"5dp\"\n            android:layout_marginRight=\"5dp\"\n            android:background=\"#efefef\"\n            android:gravity=\"center_vertical\"\n            android:paddingLeft=\"5dp\"\n            android:text=\"暂无礼包，敬请期待！\"\n            android:textColor=\"#999999\"\n            android:textSize=\"14sp\"\n            android:visibility=\"gone\" />\n\n        <ScrollView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" >\n\n            <LinearLayout\n                android:id=\"@+id/youxun_gb_ll\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\" />\n        </ScrollView>\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_menu_4.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/youxun_menu_4_ll\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:visibility=\"gone\" >\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@android:color/white\"\n        android:orientation=\"vertical\" >\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"40dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:gravity=\"center_vertical\"\n            android:text=\"客服\"\n            android:textColor=\"#666666\"\n            android:textSize=\"16sp\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dp\"\n            android:layout_marginRight=\"5dp\"\n            android:background=\"#efefef\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"horizontal\"\n            android:padding=\"10dp\" >\n\n            <ImageView\n                android:layout_width=\"80dp\"\n                android:layout_height=\"101dp\"\n                android:contentDescription=\"@null\"\n                android:src=\"@drawable/youxun_service\" />\n\n            <LinearLayout\n                android:id=\"@+id/youxun_contact_inform_ll\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"80dp\"\n                android:layout_marginLeft=\"10dp\"\n                android:background=\"@drawable/youxun_service_rect\"\n                android:gravity=\"center\"\n                android:orientation=\"vertical\" >\n\n                <TextView\n                    android:id=\"@+id/youxun_menu_4_qq\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center_vertical\"\n                    android:text=\"客服QQ：800050545\"\n                    android:textColor=\"#333333\"\n                    android:textSize=\"12sp\" />\n\n                <TextView\n                    android:id=\"@+id/youxun_menu_4_phone\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"10dp\"\n                    android:gravity=\"center_vertical\"\n                    android:text=\"客服电话：4008871822\"\n                    android:textColor=\"#333333\"\n                    android:textSize=\"12sp\" />\n            </LinearLayout>\n        </LinearLayout>\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_mobile.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\" >\n\n    <include layout=\"@layout/youxun_mobile_verify\" />\n\n    <include layout=\"@layout/youxun_mobile_reg\" />\n    \n    <include layout=\"@layout/youxun_mobile_login\" />\n\n</FrameLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_mobile_login.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/youxun_mobile_login_rl\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\"\n    android:visibility=\"gone\" >\n\n    <RelativeLayout\n        android:layout_width=\"402dp\"\n        android:layout_height=\"216dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@drawable/youxun_login_1\" >\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\" >\n\n            <ImageView\n                android:layout_width=\"116dp\"\n                android:layout_height=\"140dp\"\n                android:layout_marginTop=\"12.5dp\"\n                android:padding=\"16dp\"\n                android:src=\"@drawable/youxun_login_8\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginRight=\"10dp\"\n                android:orientation=\"vertical\" >\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"28dp\"\n                    android:layout_marginTop=\"10dp\"\n                    android:orientation=\"horizontal\" >\n\n                    <Button\n                        android:id=\"@+id/youxun_mobile_login_btn_code\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_weight=\"1.0\"\n                        android:background=\"@drawable/youxun_drawable_3\"\n                        android:text=\"验证码登录\"\n                        android:textColor=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <Button\n                        android:id=\"@+id/youxun_mobile_login_btn_pass\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_weight=\"1.0\"\n                        android:background=\"@drawable/youxun_drawable_44\"\n                        android:text=\"密码登录\"\n                        android:textColor=\"#ffffff\"\n                        android:textSize=\"14sp\" />\n                </LinearLayout>\n\n                <TextView\n                    android:id=\"@+id/youxun_mobile_login_tv\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"2dp\"\n                    android:textColor=\"#474747\"\n                    android:textSize=\"12sp\" />\n\n                <RelativeLayout\n                    android:id=\"@+id/youxun_mobile_login_code_rl\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"2dp\"\n                    android:background=\"@drawable/youxun_drawable_2\"\n                    android:visibility=\"gone\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_10\" />\n\n                    <EditText\n                        android:id=\"@+id/youxun_mobile_login_code_et\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginLeft=\"35dp\"\n                        android:layout_marginRight=\"81dp\"\n                        android:background=\"@null\"\n                        android:hint=\"请输入短信验证码\"\n                        android:imeOptions=\"flagNoExtractUi\"\n                        android:inputType=\"number\"\n                        android:maxLength=\"4\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textColorHint=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <View\n                        android:layout_width=\"1dp\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_marginBottom=\"10dp\"\n                        android:layout_marginRight=\"80dp\"\n                        android:layout_marginTop=\"10dp\"\n                        android:background=\"#c6c6c6\" />\n\n                    <Button\n                        android:id=\"@+id/youxun_mobile_login_code_btn\"\n                        android:layout_width=\"80dp\"\n                        android:layout_height=\"45dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:background=\"@null\"\n                        android:text=\"获取验证码\"\n                        android:textColor=\"#ff606d\"\n                        android:textSize=\"14sp\" />\n                </RelativeLayout>\n\n                <RelativeLayout\n                    android:id=\"@+id/youxun_mobile_login_pass_rl\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"2dp\"\n                    android:background=\"@drawable/youxun_drawable_2\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_7\" />\n\n                    <EditText\n                        android:id=\"@+id/youxun_mobile_login_pass_et\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginLeft=\"40dip\"\n                        android:layout_marginRight=\"35dp\"\n                        android:background=\"@null\"\n                        android:hint=\"请输入密码\"\n                        android:imeOptions=\"flagNoExtractUi\"\n                        android:inputType=\"textPassword\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textColorHint=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <ImageView\n                        android:id=\"@+id/youxun_mobile_login_close\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:padding=\"10dp\"\n                        android:src=\"@drawable/youxun_login_9\"\n                        android:visibility=\"gone\" />\n                </RelativeLayout>\n\n                <Button\n                    android:id=\"@+id/youxun_mobile_login_btn\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"10dp\"\n                    android:background=\"@drawable/youxun_drawable_1\"\n                    android:enabled=\"false\"\n                    android:text=\"登录\"\n                    android:textColor=\"#ffffff\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_marginBottom=\"50dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginRight=\"10dp\"\n            android:background=\"#c6c6c6\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"50dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:orientation=\"horizontal\" >\n\n            <LinearLayout\n                android:id=\"@+id/youxun_mobile_login_forget\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1.0\"\n                android:gravity=\"center\"\n                android:orientation=\"horizontal\" >\n\n                <ImageView\n                    android:layout_width=\"20dp\"\n                    android:layout_height=\"20dp\"\n                    android:src=\"@drawable/youxun_login_7\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginLeft=\"5dp\"\n                    android:text=\"忘记密码>\"\n                    android:textColor=\"#919191\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n\n            <LinearLayout\n                android:id=\"@+id/youxun_mobile_login_reg\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1.0\"\n                android:gravity=\"center\"\n                android:orientation=\"horizontal\" >\n\n                <ImageView\n                    android:layout_width=\"20dp\"\n                    android:layout_height=\"20dp\"\n                    android:src=\"@drawable/youxun_login_6\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginLeft=\"5dp\"\n                    android:text=\"账号注册>\"\n                    android:textColor=\"#919191\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <ImageButton\n            android:id=\"@+id/youxun_mobile_login_back\"\n            android:layout_width=\"25dp\"\n            android:layout_height=\"25dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginTop=\"10dp\"\n            android:background=\"@null\"\n            android:src=\"@drawable/youxun_login_5\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_mobile_reg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/youxun_mobile_reg_rl\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\"\n    android:visibility=\"gone\" >\n\n    <RelativeLayout\n        android:layout_width=\"402dp\"\n        android:layout_height=\"216dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@drawable/youxun_login_1\" >\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\" >\n\n            <ImageView\n                android:layout_width=\"116dp\"\n                android:layout_height=\"140dp\"\n                android:layout_marginTop=\"12.5dp\"\n                android:padding=\"16dp\"\n                android:src=\"@drawable/youxun_login_8\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginRight=\"10dp\"\n                android:orientation=\"vertical\" >\n\n                <TextView\n                    android:id=\"@+id/youxun_mobile_reg_tv\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"10dp\"\n                    android:textColor=\"#474747\"\n                    android:textSize=\"12sp\" />\n\n                <RelativeLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"10dp\"\n                    android:background=\"@drawable/youxun_drawable_2\" >\n\n                    <ImageView\n                        android:layout_width=\"20dp\"\n                        android:layout_height=\"20dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:src=\"@drawable/youxun_login_10\" />\n\n                    <EditText\n                        android:id=\"@+id/youxun_mobile_reg_et\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginLeft=\"35dp\"\n                        android:layout_marginRight=\"71dp\"\n                        android:background=\"@null\"\n                        android:hint=\"请输入短信验证码\"\n                        android:imeOptions=\"flagNoExtractUi\"\n                        android:inputType=\"number\"\n                        android:maxLength=\"4\"\n                        android:singleLine=\"true\"\n                        android:textColor=\"#474747\"\n                        android:textColorHint=\"#c6c6c6\"\n                        android:textSize=\"14sp\" />\n\n                    <View\n                        android:layout_width=\"1dp\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_marginBottom=\"10dp\"\n                        android:layout_marginRight=\"70dp\"\n                        android:layout_marginTop=\"10dp\"\n                        android:background=\"#c6c6c6\" />\n\n                    <Button\n                        android:id=\"@+id/youxun_mobile_reg_code\"\n                        android:layout_width=\"70dp\"\n                        android:layout_height=\"45dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:background=\"@null\"\n                        android:textColor=\"#ff606d\"\n                        android:textSize=\"14sp\" />\n                </RelativeLayout>\n\n                <Button\n                    android:id=\"@+id/youxun_mobile_reg_btn\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"10dp\"\n                    android:background=\"@drawable/youxun_drawable_1\"\n                    android:enabled=\"false\"\n                    android:text=\"注册并登录\"\n                    android:textColor=\"#ffffff\"\n                    android:textSize=\"14sp\" />\n\n                <LinearLayout\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center_horizontal\"\n                    android:orientation=\"horizontal\" >\n\n                    <RadioButton\n                        android:id=\"@+id/youxun_mobile_reg_rb\"\n                        android:layout_width=\"25dp\"\n                        android:layout_height=\"match_parent\"\n                        android:button=\"@drawable/youxun_drawable_5\"\n                        android:checked=\"true\"\n                        android:gravity=\"center_vertical\" />\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"match_parent\"\n                        android:gravity=\"center_vertical\"\n                        android:text=\"我同意 \"\n                        android:textColor=\"#474747\"\n                        android:textSize=\"12sp\" />\n\n                    <TextView\n                        android:id=\"@+id/youxun_mobile_reg_clause\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"match_parent\"\n                        android:gravity=\"center_vertical\"\n                        android:text=\" “服务条款” \"\n                        android:textColor=\"#ff606d\"\n                        android:textSize=\"12sp\" />\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"match_parent\"\n                        android:gravity=\"center_vertical\"\n                        android:text=\"和\"\n                        android:textColor=\"#474747\"\n                        android:textSize=\"12sp\" />\n\n                    <TextView\n                        android:id=\"@+id/youxun_mobile_reg_policy\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"match_parent\"\n                        android:gravity=\"center_vertical\"\n                        android:text=\" “隐私政策” \"\n                        android:textColor=\"#ff606d\"\n                        android:textSize=\"12sp\" />\n                </LinearLayout>\n            </LinearLayout>\n        </LinearLayout>\n\n        <ImageButton\n            android:id=\"@+id/youxun_mobile_reg_back\"\n            android:layout_width=\"25dp\"\n            android:layout_height=\"25dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginTop=\"10dp\"\n            android:background=\"@null\"\n            android:src=\"@drawable/youxun_login_5\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_mobile_verify.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/youxun_mobile_verify_rl\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\"\n    android:visibility=\"gone\" >\n\n    <RelativeLayout\n        android:layout_width=\"402dp\"\n        android:layout_height=\"216dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@drawable/youxun_login_1\" >\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\" >\n\n            <ImageView\n                android:layout_width=\"116dp\"\n                android:layout_height=\"140dp\"\n                android:layout_marginTop=\"12.5dp\"\n                android:padding=\"16dp\"\n                android:src=\"@drawable/youxun_login_8\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginRight=\"10dp\"\n                android:orientation=\"vertical\" >\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"10dp\"\n                    android:background=\"@drawable/youxun_drawable_2\"\n                    android:gravity=\"center_vertical\"\n                    android:orientation=\"horizontal\" >\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:text=\"+86\"\n                        android:textColor=\"#474747\"\n                        android:textSize=\"14sp\" />\n\n                    <View\n                        android:layout_width=\"1dp\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_marginBottom=\"10dp\"\n                        android:layout_marginLeft=\"5dp\"\n                        android:layout_marginTop=\"10dp\"\n                        android:background=\"#c6c6c6\" />\n\n                    <RelativeLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\" >\n\n                        <EditText\n                            android:id=\"@+id/youxun_mobile_verify_number\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"match_parent\"\n                            android:layout_marginLeft=\"5dp\"\n                            android:layout_marginRight=\"35dip\"\n                            android:background=\"@null\"\n                            android:hint=\"请输入手机号码\"\n                            android:imeOptions=\"flagNoExtractUi\"\n                            android:inputType=\"number\"\n                            android:maxLength=\"13\"\n                            android:singleLine=\"true\"\n                            android:textColor=\"#474747\"\n                            android:textColorHint=\"#c6c6c6\"\n                            android:textSize=\"14sp\" />\n\n                        <ImageView\n                            android:id=\"@+id/youxun_mobile_verify_close\"\n                            android:layout_width=\"35dp\"\n                            android:layout_height=\"35dp\"\n                            android:layout_alignParentRight=\"true\"\n                            android:layout_centerVertical=\"true\"\n                            android:padding=\"10dp\"\n                            android:src=\"@drawable/youxun_login_9\"\n                            android:visibility=\"gone\" />\n                    </RelativeLayout>\n                </LinearLayout>\n\n                <Button\n                    android:id=\"@+id/youxun_mobile_verify_next\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"45dp\"\n                    android:layout_marginTop=\"55dp\"\n                    android:background=\"@drawable/youxun_drawable_1\"\n                    android:enabled=\"false\"\n                    android:text=\"下一步\"\n                    android:textColor=\"#ffffff\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <ImageButton\n            android:id=\"@+id/youxun_mobile_verify_back\"\n            android:layout_width=\"25dp\"\n            android:layout_height=\"25dp\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginTop=\"10dp\"\n            android:background=\"@null\"\n            android:src=\"@drawable/youxun_login_5\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_notice.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\" >\n\n    <RelativeLayout\n        android:layout_width=\"492dp\"\n        android:layout_height=\"295dp\"\n        android:background=\"@drawable/youxun_notice\"\n        android:paddingLeft=\"30dp\"\n        android:paddingRight=\"30dp\"\n        android:paddingTop=\"30dp\" >\n\n        <ScrollView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginBottom=\"50dp\" >\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\" >\n\n                <TextView\n                    android:id=\"@+id/youxun_notice_tv\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:textColor=\"@android:color/black\"\n                    android:textSize=\"12sp\" />\n            </LinearLayout>\n        </ScrollView>\n\n        <Button\n            android:id=\"@+id/youxun_notice_btn\"\n            android:layout_width=\"120dp\"\n            android:layout_height=\"50dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_centerHorizontal=\"true\"\n            android:background=\"@null\" />\n    </RelativeLayout>\n\n</LinearLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_pay.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"#f9ffff\"\n    android:orientation=\"vertical\" >\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:background=\"#FF51BA8F\" >\n\n        <ImageView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerInParent=\"true\"\n            android:src=\"@drawable/youxun_pay_logo\" />\n    </RelativeLayout>\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:overScrollMode=\"never\"\n        android:scrollbars=\"none\" >\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\" >\n\n            <View\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"10dp\"\n                android:background=\"#f9ffff\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"#ffffff\"\n                android:orientation=\"vertical\" >\n\n                <View\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1px\"\n                    android:background=\"#ededed\" />\n\n                <TextView\n                    android:id=\"@+id/youxun_pay_order\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginLeft=\"10dp\"\n                    android:layout_marginTop=\"20dp\"\n                    android:lineSpacingMultiplier=\"1.3\"\n                    android:text=\"您已下单成功，订单信息如下：\\n订单编号：000\\n订单名称：000\\n订单金额：0元\"\n                    android:textColor=\"#666666\"\n                    android:textSize=\"14sp\" />\n\n                <View\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1px\"\n                    android:layout_marginTop=\"20dp\"\n                    android:background=\"#ededed\" />\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"10dp\"\n                android:layout_marginTop=\"15dp\"\n                android:orientation=\"horizontal\" >\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:lineSpacingMultiplier=\"1.2\"\n                    android:text=\"还需支付：\"\n                    android:textColor=\"#666666\"\n                    android:textSize=\"14sp\" />\n\n                <TextView\n                    android:id=\"@+id/youxun_pay_money\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:lineSpacingMultiplier=\"1.2\"\n                    android:text=\"0元\"\n                    android:textColor=\"#FFCC252D\"\n                    android:textSize=\"14sp\" />\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"15dp\"\n                android:background=\"#ffffff\"\n                android:orientation=\"vertical\" >\n\n                <View\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1px\"\n                    android:background=\"#ededed\" />\n\n                <RelativeLayout\n                    android:id=\"@+id/youxun_pay_alipay\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"10dp\" >\n\n                    <ImageView\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:contentDescription=\"@null\"\n                        android:src=\"@drawable/youxun_alipay_logo\" />\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"50dp\"\n                        android:text=\"支付宝支付\"\n                        android:textColor=\"#333333\"\n                        android:textSize=\"16sp\" />\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginRight=\"35dp\"\n                        android:text=\"推荐有支付宝用户使用\"\n                        android:textColor=\"#666666\"\n                        android:textSize=\"12sp\" />\n\n                    <ImageButton\n                        android:id=\"@+id/youxun_pay_alipay_\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:background=\"@null\"\n                        android:src=\"@drawable/youxun_deselect\" />\n                </RelativeLayout>\n\n                <View\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1px\"\n                    android:layout_marginTop=\"10dp\"\n                    android:background=\"#ededed\" />\n\n                <RelativeLayout\n                    android:id=\"@+id/youxun_pay_wechat\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"10dp\" >\n\n                    <ImageView\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:contentDescription=\"@null\"\n                        android:src=\"@drawable/youxun_wechat_logo\" />\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"50dp\"\n                        android:text=\"微信支付\"\n                        android:textColor=\"#333333\"\n                        android:textSize=\"16sp\" />\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"50dp\"\n                        android:layout_marginRight=\"35dp\"\n                        android:text=\"推荐有微信账号使用\"\n                        android:textColor=\"#666666\"\n                        android:textSize=\"12sp\" />\n\n                    <ImageButton\n                        android:id=\"@+id/youxun_pay_wechat_\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:background=\"@null\"\n                        android:src=\"@drawable/youxun_deselect\" />\n                </RelativeLayout>\n\n                <View\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1px\"\n                    android:layout_marginTop=\"10dp\"\n                    android:background=\"#ededed\" />\n                \n                <RelativeLayout\n                    android:id=\"@+id/youxun_pay_yx\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"10dp\" >\n\n                    <ImageView\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"10dp\"\n                        android:contentDescription=\"@null\"\n                        android:src=\"@drawable/youxun_yxpay\" />\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"50dp\"\n                        android:text=\"余额支付\"\n                        android:textColor=\"#333333\"\n                        android:textSize=\"16sp\" />\n\n                    <TextView\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_marginLeft=\"50dp\"\n                        android:layout_marginRight=\"35dp\"\n                        android:text=\"推荐有账号余额使用\"\n                        android:textColor=\"#666666\"\n                        android:textSize=\"12sp\" />\n\n                    <ImageButton\n                        android:id=\"@+id/youxun_pay_yx_\"\n                        android:layout_width=\"35dp\"\n                        android:layout_height=\"35dp\"\n                        android:layout_alignParentRight=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:background=\"@null\"\n                        android:src=\"@drawable/youxun_deselect\" />\n                </RelativeLayout>\n\n                <View\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"1px\"\n                    android:layout_marginTop=\"10dp\"\n                    android:background=\"#ededed\" />\n            </LinearLayout>\n\n            <Button\n                android:id=\"@+id/youxun_pay_btn\"\n                android:layout_width=\"305dp\"\n                android:layout_height=\"44dip\"\n                android:layout_gravity=\"center\"\n                android:layout_marginTop=\"30dp\"\n                android:background=\"@drawable/youxun_pay_btn\"\n                android:text=\"立即支付\"\n                android:textColor=\"@android:color/white\"\n                android:textSize=\"16sp\" />\n\n            <View\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"10dp\"\n                android:background=\"#f9ffff\" />\n        </LinearLayout>\n    </ScrollView>\n\n</LinearLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_toast.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\" >\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"#66000000\"\n        android:gravity=\"center\"\n        android:orientation=\"horizontal\"\n        android:padding=\"25dp\" >\n\n        <TextView\n            android:id=\"@+id/youxun_toast_tv\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textColor=\"#ffffff\"\n            android:textSize=\"18sp\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/main/res/layout/youxun_webview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/white\"\n    android:orientation=\"vertical\" >\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:background=\"#f8f8f8\" >\n\n        <ImageView\n            android:id=\"@+id/youxun_webview_back\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:layout_centerVertical=\"true\"\n            android:padding=\"5dp\"\n            android:src=\"@drawable/youxun_login_5\" />\n\n        <ImageView\n            android:id=\"@+id/youxun_webview_icon\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginLeft=\"40dp\" />\n\n        <TextView\n            android:id=\"@+id/youxun_webview_title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginLeft=\"85dp\"\n            android:textColor=\"#212121\"\n            android:textSize=\"14sp\" />\n\n        <TextView\n            android:id=\"@+id/youxun_webview_sw\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"40dp\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginRight=\"10dp\"\n            android:gravity=\"center\"\n            android:text=\"切换账号\"\n            android:textColor=\"#ff606d\"\n            android:textSize=\"14sp\"\n            android:visibility=\"gone\" />\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:background=\"#d2d2d2\" />\n    </RelativeLayout>\n\n    <WebView\n        android:id=\"@+id/youxun_webview_wv\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n</LinearLayout>"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/src/test/java/com/bzai/gamesdk/channel/test/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdk.channel.test;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Lexiang/开发者说明",
    "content": "\n\n未避免后续SDK开发的同学开发和维护时，逻辑上能有个清晰的认知，这份说明文件必读!!!\n\nSYSDK_Channel_LeXiang: 乐享渠道SDK\n\n----------------------------------------------------------------------------------------------\n\n   乐享SDK -- V1.0.0 -- bzai     2018.04.16\n\n   1、乐享SDK新接入，暂未注意事项\n\n\n----------------------------------------------------------------------------------------------\n\n   后续项目待续。。。"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Test/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Test/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDK_Utils')\n}\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Test/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Test/src/androidTest/java/com/bzai/gamesdk/channel/test/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdk.channel.test;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdk.channel.test.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Test/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.channel.test\" />\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Test/src/main/assets/Channel_config.txt",
    "content": "{\n    \"channel\": [\n        {\n            \"channel_name\": \"channel\",\n            \"class_name\": \"com.bzai.gamesdk.channel.test.TestChannelSDK\",\n            \"description\": \"测试渠道SDK\",\n            \"version\": \"1.0.0\"\n        }\n    ]\n}"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Test/src/main/java/com/bzai/gamesdk/channel/application/ChannelApplication.java",
    "content": "package com.bzai.gamesdk.channel.application;\n\nimport android.app.Application;\nimport android.content.Context;\n\n/**\n * Created by bzai on 2018/4/11.\n * <p>\n * Desc:\n *\n *  预留用于继承渠道的Application\n */\n\npublic class ChannelApplication extends Application {\n\n    @Override\n    protected void attachBaseContext(Context base) {\n        super.attachBaseContext(base);\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Test/src/main/java/com/bzai/gamesdk/channel/test/TestChannelSDK.java",
    "content": "package com.bzai.gamesdk.channel.test;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.text.method.PasswordTransformationMethod;\nimport android.view.Display;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.Window;\nimport android.view.WindowManager;\nimport android.widget.ArrayAdapter;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.Spinner;\n\nimport com.bzai.gamesdk.common.utils_base.config.TypeConfig;\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.parse.channel.Channel;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.HashMap;\n\n/**\n * Created by bzai on 2018/7/10.\n * <p>\n * Desc:\n *\n *   测试渠道SDK\n */\n\npublic class TestChannelSDK extends Channel {\n\n    private final String TAG = getClass().getSimpleName();\n\n    @Override\n    protected void initChannel() {\n        LogUtils.d(TAG, getClass().getSimpleName() + \" has init\");\n    }\n\n    @Override\n    public String getChannelID() {\n        return \"1\";\n    }\n\n    @Override\n    public boolean isSupport(int FuncType) {\n\n        switch (FuncType){\n            case TypeConfig.FUNC_SWITCHACCOUNT:\n                return true;\n\n            case TypeConfig.FUNC_LOGOUT:\n                return true;\n\n            case TypeConfig.FUNC_SHOW_FLOATWINDOW:\n                return true;\n\n            case TypeConfig.FUNC_DISMISS_FLOATWINDOW:\n                return true;\n\n            default:\n                return false;\n        }\n    }\n\n    @Override\n    public void init(Context context, HashMap<String, Object> initMap, CallBackListener initCallBackListener) {\n        LogUtils.d(TAG,getClass().getSimpleName() + \" init\");\n        initOnSuccess(initCallBackListener);\n    }\n\n    @Override\n    public void login(Context context, HashMap<String, Object> loginMap, CallBackListener loginCallBackListener) {\n        LogUtils.d(TAG,getClass().getSimpleName() + \" login\");\n        showLoginView(context,loginCallBackListener);\n    }\n\n    @Override\n    public void switchAccount(final Context context, final CallBackListener changeAccountCallBackLister) {\n\n        LogUtils.d(TAG,getClass().getSimpleName() + \" switchAccount\");\n        AlertDialog.Builder builder = new AlertDialog.Builder(context);\n        builder.setMessage(\"是否切换账号?\");\n        builder.setTitle(\"切换账号\");\n        builder.setPositiveButton(\"切换账号\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int index) {\n                        showLoginView(context,changeAccountCallBackLister);\n                    }\n                });\n        builder.setNegativeButton(\"取消\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int index) {\n                        switchAccountOnCancel(\"channel switchAccount cancel\",changeAccountCallBackLister);\n                    }\n                });\n        builder.create().show();\n    }\n\n    @Override\n    public void logout(Context context, final CallBackListener logoutCallBackLister) {\n\n        LogUtils.d(TAG,getClass().getSimpleName() + \" logout\");\n        AlertDialog.Builder builder = new AlertDialog.Builder(context);\n        builder.setMessage(\"是否注销账号?\");\n        builder.setTitle(\"注销账号\");\n        builder.setPositiveButton(\"成功\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int index) {\n                        logoutOnSuccess(logoutCallBackLister);\n                    }\n                });\n        builder.setNegativeButton(\"失败\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int index) {\n                        logoutOnFail(\"channel logout fail\",logoutCallBackLister);\n                    }\n                });\n        builder.create().show();\n\n    }\n\n    @Override\n    public void pay(Context context, HashMap<String, Object> payMap, final CallBackListener payCallBackListener) {\n\n        LogUtils.d(TAG,getClass().getSimpleName() + \" pay\");\n\n        String orderID = (String) payMap.get(\"orderId\");\n        String productName = (String) payMap.get(\"productName\");\n        String productDesc = (String) payMap.get(\"productDesc\");\n        String money = String.valueOf(payMap.get(\"money\"));\n        String productID = String.valueOf(payMap.get(\"productID\"));\n        LogUtils.d(TAG,productID);\n\n        final HashMap<String,Object> paymap = new HashMap<>();\n        paymap.put(\"orderID\",orderID);\n        paymap.put(\"productName\",productName);\n        paymap.put(\"money\",money);\n\n        AlertDialog.Builder builder = new AlertDialog.Builder(context);\n        String message = \"充值金额：\" + money\n                + \"\\n商品名称：\" + productName\n                + \"\\n商品数量：\" + \"1\"\n                + \"\\n资费说明：\" + productDesc;\n        builder.setMessage(message);\n        builder.setTitle(\"请确认充值信息\");\n        builder.setPositiveButton(\"确定\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(final DialogInterface dialog, int index) {\n                        payOnSuccess(payCallBackListener);\n                    }\n                });\n        builder.setNegativeButton(\"取消\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int index) {\n                        OnCancel(payCallBackListener);\n                    }\n                });\n        builder.create().show();\n\n    }\n\n\n    private void showLoginView(final Context context, final CallBackListener loginCallBackListener){\n\n        AlertDialog.Builder builder = new AlertDialog.Builder(context);\n        builder.setMessage(\"是否登录?\");\n        builder.setTitle(\"登录界面\");\n        builder.setPositiveButton(\"登录\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int index) {\n                        JSONObject json = new JSONObject();\n                        try {\n                            json.put(\"sid\", \"testID\");\n                        } catch (JSONException e) {\n                            e.printStackTrace();\n                        }\n\n                        loginOnSuccess(json.toString(),loginCallBackListener);\n                    }\n                });\n        builder.setNegativeButton(\"取消\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int index) {\n                        loginOnFail(\"channel login fail\",loginCallBackListener);\n                    }\n                });\n        builder.create().show();\n\n    }\n\n\n    @Override\n    public void exit(Context context, CallBackListener exitCallBackLister) {\n        LogUtils.d(TAG,getClass().getSimpleName() + \" exit\");\n        channelNotExitDialog(exitCallBackLister);\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Test/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">GameSDK_Channel_Test</string>\n</resources>\n"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Test/src/test/java/com/bzai/gamesdk/channel/test/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdk.channel.test;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDK_Channel/GameSDK_Channel_Test/开发者说明",
    "content": "\n\n未避免后续SDK开发的同学开发和维护时，逻辑上能有个清晰的认知，这份说明文件必读!!!\n\nSYSDK_Channel_Test: 模拟测试渠道SDK\n\n----------------------------------------------------------------------------------------------\n\n   模拟测试渠道SDK -- V1.0.0 -- bzai    2018.04.16\n\n   1、乐享SDK新接入，暂未注意事项\n\n\n----------------------------------------------------------------------------------------------\n\n   后续项目待续。。。"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Account/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Account/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDK_Manager_Impl')\n    compile project(':GameSDK_Utils')\n}\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Account/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Account/src/androidTest/java/com/bzai/gamesdk/module/account/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdk.module.account;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdk.module.account.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Account/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.module.account\" />\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Account/src/main/java/com/bzai/gamesdk/module/account/AccountManager.java",
    "content": "package com.bzai.gamesdk.module.account;\n\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\n\nimport com.bzai.gamesdk.common.utils_base.config.ErrCode;\nimport com.bzai.gamesdk.common.utils_base.config.TypeConfig;\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\nimport com.bzai.gamesdk.common.utils_business.cache.BaseCache;\nimport com.bzai.gamesdk.common.utils_business.config.KeyConfig;\nimport com.bzai.gamesdk.module.account.bean.AccountBean;\nimport com.bzai.gamesdk.module.account.bean.AccountCallBackBean;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.HashMap;\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc:\n *\n *  账号管理类，管理SDK的各个功能接口：登录、切换账号、注销账号、绑定账号。\n *\n *  注意可能还会有各个复杂的登录、绑定等逻辑。\n *\n *  后续项目待定\n *\n */\n\npublic class AccountManager {\n\n    public static final String TAG = \"AccountManager\";\n\n    private volatile static AccountManager INSTANCE;\n\n    private AccountManager() {\n    }\n\n    public static AccountManager getInstance() {\n        if (INSTANCE == null) {\n            synchronized (AccountManager.class) {\n                if (INSTANCE == null) {\n                    INSTANCE = new AccountManager();\n                }\n            }\n        }\n        return INSTANCE;\n    }\n\n    private Activity mActivity;\n    private AccountBean mLoginInfo; //当前登陆的登陆信息\n    private boolean isSwitchAccount = false; //通过标记位来判断是否是切换账号按钮的登录回调\n\n\n    /******************************************      获取Project账号监听     ****************************************/\n\n    private CallBackListener projectLoginCallBackListener;\n    public void setLoginCallBackLister(CallBackListener callBackLister){\n        projectLoginCallBackListener = callBackLister;\n    }\n\n    private void CallBackToProject(int event, int code, AccountBean accountBean, String msg){\n\n        //设置回调信息\n        AccountCallBackBean accountCallBackBean = new AccountCallBackBean();\n        accountCallBackBean.setEvent(event); //事件类型ID\n        accountCallBackBean.setErrorCode(code); //事件码\n        accountCallBackBean.setAccountBean(accountBean); //事件的账号信息\n        accountCallBackBean.setMsg(msg); //设置事件的信息\n\n        if (projectLoginCallBackListener != null){\n            projectLoginCallBackListener.onSuccess(accountCallBackBean);//回调给Project的信息\n        }\n    }\n\n\n    /**\n     * 登录结果监听\n     */\n    private CallBackListener LoginCallBackLister = new CallBackListener<AccountBean>(){\n\n        @Override\n        public void onSuccess(AccountBean loginInfo) {\n            LogUtils.d(TAG, \"loginInfo：\" + loginInfo.toString());\n\n            mLoginInfo = loginInfo;\n            //登陆成功，设置登录信息\n            setLoginSuccess(loginInfo);\n\n            if (isSwitchAccount){\n                CallBackToProject(TypeConfig.SWITCHACCOUNT, ErrCode.SUCCESS,loginInfo, \"user switchAccount success\");\n                isSwitchAccount = false; //置为false\n\n            }else {\n                CallBackToProject(TypeConfig.LOGIN,ErrCode.SUCCESS,loginInfo, \"user login success\");\n            }\n        }\n\n        @Override\n        public void onFailure(int code, String msg) {\n            mLoginInfo = null; //当前登陆失败就置为null\n\n            if (isSwitchAccount){\n\n                if (code == ErrCode.CANCEL){ //如果切换账号时,不走登录,给登出回调\n                    CallBackToProject(TypeConfig.LOGOUT, ErrCode.SUCCESS, null, \"user logout success\");\n\n                }else {\n                    CallBackToProject(TypeConfig.SWITCHACCOUNT, code, null, msg);\n                }\n\n            }else {\n                CallBackToProject(TypeConfig.LOGIN, code, null, msg);\n            }\n        }\n    };\n\n    /******************************************      登录     ****************************************/\n\n\n    /**\n     * 显示登录界面\n     */\n    public void showLoginView(final Activity activity, HashMap<String,Object> loginMap){\n        mActivity = activity;\n\n\n        AlertDialog.Builder builder = new AlertDialog.Builder(activity);\n        builder.setMessage(\"是否登录?\");\n        builder.setTitle(\"登录界面\");\n        builder.setPositiveButton(\"登录\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int index) {\n\n                        AccountBean loginInfo = new AccountBean();\n                        loginInfo.setLoginState(true); //将登录成功状态返回\n                        loginInfo.setUserToken(\"dasfkaf-SAFA-kfad\");\n                        loginInfo.setUserID(\"userID-123\");\n                        loginInfo.setUserName(\"测试用户\"); //聚合将用名设置为UserID\n                        LoginCallBackLister.onSuccess(loginInfo);\n\n                    }\n                });\n        builder.setNegativeButton(\"取消\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int index) {\n                        LoginCallBackLister.onFailure(ErrCode.FAILURE,\"login fail\");\n                    }\n                });\n        builder.create().show();\n\n    }\n\n\n    /**\n     * 授权登录,具体项目具体实现逻辑\n     */\n    public void authLogin(Activity activity, HashMap<String,Object> loginMap){\n        mActivity = activity;\n\n        AccountBean loginInfo = new AccountBean();\n        loginInfo.setLoginState(true); //将登录成功状态返回\n        loginInfo.setUserToken(\"dasfkaf-SAFA-kfad\");\n        loginInfo.setUserID(\"userID-123\");\n        loginInfo.setUserName(\"测试用户\"); //聚合将用名设置为UserID\n\n        LoginCallBackLister.onSuccess(loginInfo);\n    }\n\n\n    /**\n     * 获取当前登陆状态,默认false\n     * @return\n     */\n    public boolean getLoginState() {\n        if (mLoginInfo != null){\n            return mLoginInfo.getLoginState();\n        }\n        return false;\n    }\n\n    /******************************************      切换账号    ****************************************/\n\n    /**\n     * 切换账号\n     * @param activity\n     */\n    public void switchAccount(Activity activity){\n\n        mActivity = activity;\n\n        //先走登出逻辑\n        mLoginInfo = null; //登录信息清空\n        isSwitchAccount = true;\n        clearLoginInfo(activity);\n    }\n\n\n    /******************************************      登出   ****************************************/\n\n    /**\n     * 账号登出\n     */\n    public void logout(Activity activity){\n\n        mActivity = activity;\n\n        mLoginInfo = null; //登录信息清空\n        isSwitchAccount = false;\n        clearLoginInfo(activity);\n\n        CallBackToProject(TypeConfig.LOGOUT, ErrCode.SUCCESS, null, \"user logout success\");\n    }\n\n\n    /**\n     * 设置登录成功行为\n     */\n    private void setLoginSuccess(AccountBean loginInfo){\n\n        if (loginInfo != null){\n            BaseCache.getInstance().put(KeyConfig.PLAYER_ID,loginInfo.getUserID());\n            BaseCache.getInstance().put(KeyConfig.PLAYER_NAME,loginInfo.getUserName());\n            BaseCache.getInstance().put(KeyConfig.PLAYER_TOKEN,loginInfo.getUserToken());\n\n            //将当前状态存储到全局变量供其他模块插件使用\n            BaseCache.getInstance().put(KeyConfig.IS_LOGIN, getLoginState());\n        }\n    }\n\n\n    /**\n     * 清空登陆信息\n     */\n    private void clearLoginInfo(Activity activity){\n\n        mLoginInfo = null;\n\n        //清空内存的用户信息\n        BaseCache.getInstance().put(KeyConfig.PLAYER_ID,\"\");\n        BaseCache.getInstance().put(KeyConfig.PLAYER_NAME,\"\");\n        BaseCache.getInstance().put(KeyConfig.PLAYER_TOKEN,\"\");\n\n        //将当前状态存储到全局变量供其他模块插件使用\n        BaseCache.getInstance().put(KeyConfig.IS_LOGIN, getLoginState());\n\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Account/src/main/java/com/bzai/gamesdk/module/account/bean/AccountBean.java",
    "content": "package com.bzai.gamesdk.module.account.bean;\n\n\n/**\n * Created by bzai on 2018/4/11.\n * <p>\n * Desc:\n *\n *  登录信息，封装服务端返回信息，用于对接Project的公开实体\n *  (后续注意不同项目的字段)\n *\n */\n\npublic class AccountBean{\n\n    private boolean loginState; //当前登陆状态\n    private String userID;\n    private String userName;\n    private String userToken;\n\n    public boolean getLoginState() {\n        return loginState;\n    }\n\n    public void setLoginState(boolean loginState) {\n        this.loginState = loginState;\n    }\n\n    public String getUserID() {\n        return userID;\n    }\n\n    public void setUserID(String userID) {\n        this.userID = userID;\n    }\n\n    public String getUserName() {\n        return userName;\n    }\n\n    public void setUserName(String userName) {\n        this.userName = userName;\n    }\n\n    public String getUserToken() {\n        return userToken;\n    }\n\n    public void setUserToken(String userToken) {\n        this.userToken = userToken;\n    }\n\n    @Override\n    public String toString() {\n        return \"AccountBean {\" + \"userID=\" + userID\n                + \", userName=\" + userName\n                + \", userToken=\" + userToken + '}';\n    }\n}\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Account/src/main/java/com/bzai/gamesdk/module/account/bean/AccountCallBackBean.java",
    "content": "package com.bzai.gamesdk.module.account.bean;\n\n/**\n * Created by bzai on 2018/6/7.\n * <p>\n * Desc:\n *\n *    账号事件回调实体\n */\n\npublic class AccountCallBackBean {\n\n    private int event;\n    private AccountBean accountBean; //账号信息\n    private int errorCode; //错误码\n    private String msg; // 错误信息\n\n    public int getEvent() {\n        return event;\n    }\n\n    public void setEvent(int event) {\n        this.event = event;\n    }\n\n    public AccountBean getAccountBean() {\n        return accountBean;\n    }\n\n    public void setAccountBean(AccountBean accountBean) {\n        this.accountBean = accountBean;\n    }\n\n    public int getErrorCode() {\n        return errorCode;\n    }\n\n    public void setErrorCode(int errorCode) {\n        this.errorCode = errorCode;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    public void setMsg(String msg) {\n        this.msg = msg;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Account/src/test/java/com/bzai/gamesdk/module/account/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdk.module.account;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Init/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Init/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDK_Manager_Impl')\n    compile project(':GameSDK_Utils')\n}\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Init/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Init/src/androidTest/java/com/bzai/gamesdk/module/init/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdk.module.init;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdk.module.init.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Init/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.module.init\" />\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Init/src/main/java/com/bzai/gamesdk/module/init/InitManager.java",
    "content": "package com.bzai.gamesdk.module.init;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.content.Context;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.Process;\n\nimport com.bzai.gamesdk.common.utils_base.cache.ApplicationCache;\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.parse.channel.ChannelManager;\nimport com.bzai.gamesdk.common.utils_base.parse.plugin.PluginManager;\nimport com.bzai.gamesdk.common.utils_base.parse.project.ProjectManager;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\nimport com.bzai.gamesdk.common.utils_business.cache.BaseCache;\nimport com.bzai.gamesdk.common.utils_business.cache.SDKInfoCache;\nimport com.bzai.gamesdk.common.utils_business.cache.SharePreferencesCache;\nimport com.bzai.gamesdk.common.utils_business.config.KeyConfig;\nimport com.bzai.gamesdk.common.utils_business.config.UrlConfig;\n\n/**\n * Created by bzai on 2018/7/19.\n * <p>\n * Desc: SDK初始化逻辑\n *\n *   后续可能还会有复杂的初始化事情要做\n *   如：初始化获取后台开关、切换域名、获取权限等。\n */\npublic class InitManager {\n\n    private final String TAG = getClass().getSimpleName();\n\n    private volatile static InitManager INSTANCE;\n\n    private InitManager() {\n    }\n\n    public static InitManager getInstance() {\n        if (INSTANCE == null) {\n            synchronized (InitManager.class) {\n                if (INSTANCE == null) {\n                    INSTANCE = new InitManager();\n                }\n            }\n        }\n        return INSTANCE;\n    }\n\n    /**\n     * 加载SDK项目配置入口插件(这是项目最开始加载的)\n     * @param context 上下文\n     * @param isdebug 日志调试开关\n     */\n    public void initApplication(Application cxt, Context context, boolean isdebug){\n\n        ApplicationCache.init(cxt);\n        LogUtils.setDebugLogModel(isdebug);\n        ProjectManager.init(context).loadAllProjects();\n        //聚合SDK加载渠道插件\n        ChannelManager.init(context).loadChannel();\n    }\n\n\n    private static Handler sApiHandler;\n    private static boolean initState = false;\n\n    /**\n     * SDK初始化逻辑\n     * @param activity\n     * @param callBackListener\n     */\n    public void init(final Activity activity, final String gameid, final String gamekey, final CallBackListener callBackListener) {\n\n        if (sApiHandler == null) {\n            HandlerThread ht = new HandlerThread(\"project_sdk_thread\",\n                    Process.THREAD_PRIORITY_BACKGROUND);\n            ht.start();\n            sApiHandler = new Handler(ht.getLooper());\n        }\n\n        Runnable r = new Runnable() {\n            @Override\n            public void run() {\n\n                //1、初始化全局缓存变量\n                BaseCache.init(activity.getApplication());\n                BaseCache.getInstance().put(KeyConfig.GAME_ID,gameid);\n                BaseCache.getInstance().put(KeyConfig.GAME_KEY,gamekey);\n\n                //2、初始化SDK参数\n                SDKInfoCache.getDefault(activity.getApplication());\n\n                //3、初始化持久化数据\n                SharePreferencesCache spCache = new SharePreferencesCache(activity);\n                spCache.init();\n\n                //4、加载功能插件\n                PluginManager.init(activity).loadAllPlugins();\n\n                //5、初始化域名配置\n                UrlConfig.initUrl();\n\n                //6、开始初始化逻辑\n                startInitLogic(activity,callBackListener);\n\n            }\n        };\n        sApiHandler.post(r);\n    }\n\n\n    /**\n     * 真正的初始化逻辑\n     */\n    private void startInitLogic(final Activity activity, final CallBackListener callBackListener){\n\n        //-----------------------------已初始化完成--------------------------------\n        activity.runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                setInitState(true);\n                callBackListener.onSuccess(null);\n            }\n        });\n    }\n\n    /**\n     * 初始化功能插件()\n     */\n    private void initFunctionPlugin(Activity activity){\n\n        //腾讯bugly日志收集\n\n    }\n\n\n    public void setInitState(boolean state) {\n        initState = state;\n        //将当前状态存储到全局变量供其他模块插件使用\n        BaseCache.getInstance().put(KeyConfig.IS_INIT,initState);\n    }\n\n    public boolean getInitState() {\n        return initState;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Init/src/test/java/com/bzai/gamesdk/module/init/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdk.module.init;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Purchase/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Purchase/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDK_Manager_Impl')\n    compile project(':GameSDK_Utils')\n}\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Purchase/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Purchase/src/androidTest/java/com/bzai/gamesdk/module/purchase/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdk.module.purchase;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdk.module.purchase.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Purchase/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.module.purchase\" />\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Purchase/src/main/java/com/bzai/gamesdk/module/purchase/PurchaseManager.java",
    "content": "package com.bzai.gamesdk.module.purchase;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\n\n\nimport com.bzai.gamesdk.common.utils_base.config.ErrCode;\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport java.util.HashMap;\n\n/**\n * Created by bzai on 2018/4/11.\n * <p>\n * Desc:\n *\n *  购买管理类，管理SDK的各个购买功能接口：创建订单、三方支付、运营商支付、渠道支付、补单逻辑、包月、订阅等。\n *\n *  注意可能还会有各个复杂的支付逻辑: 可能会先短代支付、然后渠道支付、三方支付，还有后台切换支付开关等。\n *\n *  后续项目待定\n */\n\npublic class PurchaseManager {\n\n    public static final String TAG = \"PurchaseManager\";\n\n    private volatile static PurchaseManager INSTANCE;\n\n    private PurchaseManager() {\n    }\n\n    public static PurchaseManager getInstance() {\n        if (INSTANCE == null) {\n            synchronized (PurchaseManager.class) {\n                if (INSTANCE == null) {\n                    INSTANCE = new PurchaseManager();\n                }\n            }\n        }\n        return INSTANCE;\n    }\n\n    /**\n     * 创建订单,具体项目具体实现\n     */\n    public void createOrderId(Activity activity, HashMap<String, Object> payParams , final CallBackListener callBackListener){\n\n        LogUtils.debug_d(TAG,\"payParams = \" + payParams.toString());\n        String orderID = \"DD1441\";\n        callBackListener.onSuccess(orderID);\n\n    }\n\n    /**\n     * 显示支付界面\n     */\n    public void showPayView(Activity activity, HashMap<String, Object> payParams, final CallBackListener callBackListener){\n        LogUtils.debug_d(TAG,\"payParams = \" + payParams.toString());\n\n        AlertDialog.Builder builder = new AlertDialog.Builder(activity);\n        String message = \"充值金额：\" + \"2\"\n                + \"\\n商品名称：\" + \"大饼\"\n                + \"\\n商品数量：\" + \"1\"\n                + \"\\n资费说明：\" + \"2元\";\n        builder.setMessage(message);\n        builder.setTitle(\"请确认充值信息\");\n        builder.setPositiveButton(\"确定\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(final DialogInterface dialog, int index) {\n                        //支付结果回调到这里来\n                        PurchaseResult purchaseResult = new PurchaseResult(PurchaseResult.PurchaseState,null);\n                        callBackListener.onSuccess(purchaseResult);\n                    }\n                });\n        builder.setNegativeButton(\"取消\",\n                new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int index) {\n                        callBackListener.onFailure(ErrCode.FAILURE,\"pay fail\");\n                    }\n                });\n        builder.create().show();\n\n    }\n}\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Purchase/src/main/java/com/bzai/gamesdk/module/purchase/PurchaseResult.java",
    "content": "package com.bzai.gamesdk.module.purchase;\n\n/**\n * Created by bzai on 2018/4/13.\n * <p>\n * Desc:\n *\n *  用于描述支付回调的信息\n *\n */\n\npublic class PurchaseResult {\n\n    public static final int OrderState = 1; // 创建订单成功\n    public static final int PurchaseState = 2; // 支付结果\n\n    public int status;\n    public Object message;\n\n    public PurchaseResult(int status, Object message) {\n\n        this.status = status;\n        this.message = message;\n\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Purchase/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">GameSDK_Module_Purchase</string>\n</resources>\n"
  },
  {
    "path": "GameSDK_Manager/GameSDK_Module_Purchase/src/test/java/com/bzai/gamesdk/module/purchase/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdk.module.purchase;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDK_Manager_Impl/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDK_Manager_Impl/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDK_Plugin_Alipay')\n    compile project(':GameSDK_Plugin_Wechat')\n}\n"
  },
  {
    "path": "GameSDK_Manager_Impl/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDK_Manager_Impl/src/androidTest/java/com/bzai/gamesdk/manager/impl/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdk.manager.impl;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdk.manager.impl.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDK_Manager_Impl/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.manager.impl\" />\n"
  },
  {
    "path": "GameSDK_Manager_Impl/src/main/java/com/bzai/gamesdk/invoke/plugin/AlipayPluginApi.java",
    "content": "package com.bzai.gamesdk.invoke.plugin;\n\nimport android.content.Context;\n\n\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.parse.plugin.Plugin;\nimport com.bzai.gamesdk.common.utils_base.parse.plugin.PluginManager;\nimport com.bzai.gamesdk.common.utils_base.parse.plugin.PluginReflectApi;\n\nimport java.util.Map;\n\n/**\n * Created by bzai on 2018/6/21.\n * <p>\n * Desc:\n *\n *  对接支付宝功能插件的api,反射调用\n */\n\npublic class AlipayPluginApi extends PluginReflectApi {\n\n    private String TAG = \"AlipayPluginApi\";\n\n    private Plugin alipayPlugin;\n\n    private volatile static AlipayPluginApi INSTANCE;\n\n    private AlipayPluginApi() {\n        alipayPlugin = PluginManager.getInstance().getPlugin(\"plugin_alipay\");\n    }\n\n    public static AlipayPluginApi getInstance() {\n        if (INSTANCE == null) {\n            synchronized (WechatPluginApi.class) {\n                if (INSTANCE == null) {\n                    INSTANCE = new AlipayPluginApi();\n                }\n            }\n        }\n        return INSTANCE;\n    }\n\n    /**\n     * 调用支付宝app支付\n     */\n    public void pay(Context context, Map<String,Object> map, CallBackListener callBackListener){\n\n        if (alipayPlugin != null){\n            invoke(alipayPlugin,\"alipay\",new Class<?>[]{Context.class, Map.class, CallBackListener.class},\n                    new Object[]{context, map, callBackListener});\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Manager_Impl/src/main/java/com/bzai/gamesdk/invoke/plugin/WechatPluginApi.java",
    "content": "package com.bzai.gamesdk.invoke.plugin;\n\nimport android.content.Context;\n\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.parse.plugin.Plugin;\nimport com.bzai.gamesdk.common.utils_base.parse.plugin.PluginManager;\nimport com.bzai.gamesdk.common.utils_base.parse.plugin.PluginReflectApi;\n\nimport java.util.Map;\n\n/**\n * Created by bzai on 2018/6/21.\n * <p>\n * Desc:\n *\n *   对接微信功能插件的api,反射调用\n */\n\npublic class WechatPluginApi extends PluginReflectApi {\n\n    private String TAG = \"WechatPluginApi\";\n\n    private Plugin wechatPlugin;\n\n    private volatile static WechatPluginApi INSTANCE;\n\n    private WechatPluginApi() {\n        wechatPlugin = PluginManager.getInstance().getPlugin(\"plugin_wechat\");\n    }\n\n    public static WechatPluginApi getInstance() {\n        if (INSTANCE == null) {\n            synchronized (WechatPluginApi.class) {\n                if (INSTANCE == null) {\n                    INSTANCE = new WechatPluginApi();\n                }\n            }\n        }\n        return INSTANCE;\n    }\n\n    /**\n     * 调用微信app支付\n     */\n    public void pay(Context context, Map<String,Object> map, CallBackListener callBackListener){\n\n        if (wechatPlugin != null){\n            invoke(wechatPlugin,\"wechatPay\",new Class<?>[]{Context.class, Map.class, CallBackListener.class},\n                    new Object[]{context, map, callBackListener});\n        }\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Manager_Impl/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">GameSDK_Manager_Impl</string>\n</resources>\n"
  },
  {
    "path": "GameSDK_Manager_Impl/src/test/java/com/bzai/gamesdk/manager/impl/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdk.manager.impl;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Alipay/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Alipay/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDK_Utils')\n\n}\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Alipay/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Alipay/src/androidTest/java/com/bzai/gamesdk/plugin/alipay/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdk.plugin.alipay;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdk.plugin.alipay.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Alipay/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.plugin.alipay\" />\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Alipay/src/main/java/com/bzai/gamesdk/plugin/alipay/AlipayPlugin.java",
    "content": "package com.bzai.gamesdk.plugin.alipay;\n\nimport android.content.Context;\n\n\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.parse.plugin.Plugin;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport java.util.Map;\n\n/**\n * Created by bzai on 2018/6/21.\n * <p>\n * Desc:\n *\n *  支付宝功能插件,方便后后续添加登录接口，支付(H5支付)接口，统计接口\n */\n\npublic class AlipayPlugin extends Plugin {\n\n    private String TAG = \"AlipayPlugin\";\n\n    @Override\n    protected synchronized void initPlugin() {\n        super.initPlugin();\n        LogUtils.d(TAG,\"init \" + getClass().getSimpleName());\n    }\n\n    /**\n     * 调用支付宝支付app接口\n     */\n    public void alipay(Context context, Map<String,Object> payMap, CallBackListener callBackListener){\n//        AlipayPay.getInstance().pay(context,payMap,callBackListener);\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Alipay/src/main/java/com/bzai/gamesdk/plugin/alipay/pay/AlipayPay.java",
    "content": "package com.bzai.gamesdk.plugin.alipay.pay;\n\nimport android.annotation.SuppressLint;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.os.Handler;\nimport android.os.Message;\nimport android.text.TextUtils;\n\nimport com.alipay.sdk.app.PayTask;\nimport com.bzai.gamesdk.common.utils_base.config.ErrCode;\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLDecoder;\nimport java.util.Map;\n\n/**\n * Created by bzai on 2018/6/23.\n * <p>\n * Desc:\n *\n *     支付包支付\n */\n\npublic class AlipayPay {\n\n    public String TAG = \"AlipayPay\";\n\n    private volatile static AlipayPay INSTANCE;\n\n    private AlipayPay() {\n    }\n\n    public static AlipayPay getInstance() {\n        if (INSTANCE == null) {\n            synchronized (AlipayPay.class) {\n                if (INSTANCE == null) {\n                    INSTANCE = new AlipayPay();\n                }\n            }\n        }\n        return INSTANCE;\n    }\n\n    private static final int SDK_PAY_FLAG = 1;\n\n    private CallBackListener paycallback;\n\n    /**\n     * 支付包app支付\n     */\n    public void pay(final Context context, Map<String,Object> payMap, CallBackListener callBackListener){\n\n        paycallback = callBackListener;\n\n        String alipayOrderInfo = String.valueOf(payMap.get(\"payment_info\"));\n\n        //日志打印下,不传如支付订单里\n        try {\n            LogUtils.d(TAG,\"alipayOrderInfo\" + URLDecoder.decode(alipayOrderInfo, \"UTF-8\"));\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n\n        final String orderInfo = alipayOrderInfo;\n        Runnable payRunnable = new Runnable() {\n\n            @Override\n            public void run() {\n                PayTask alipay = new PayTask((Activity) context);\n                Map<String, String> result = alipay.payV2(orderInfo, true);\n\n                Message msg = new Message();\n                msg.what = SDK_PAY_FLAG;\n                msg.obj = result;\n                mHandler.sendMessage(msg);\n            }\n        };\n\n        Thread payThread = new Thread(payRunnable);\n        payThread.start();\n    }\n\n    @SuppressLint(\"HandlerLeak\")\n    private Handler mHandler = new Handler() {\n\n        @Override\n        public void handleMessage(Message msg) {\n            switch (msg.what) {\n                case SDK_PAY_FLAG: {\n                    @SuppressWarnings(\"unchecked\")\n                    PayResult payResult = new PayResult((Map<String, String>) msg.obj);\n\n                    /**\n                     对于支付结果，请商户依赖服务端的异步通知结果。同步通知结果，仅作为支付结束的通知。\n                     */\n                    String resultInfo = payResult.getResult();// 同步返回需要验证的信息\n                    String resultStatus = payResult.getResultStatus();\n                    // 判断resultStatus 为9000则代表支付成功\n                    if (TextUtils.equals(resultStatus, \"9000\")) {\n                        paycallback.onSuccess(null);\n\n                    } else if (TextUtils.equals(resultStatus, \"6001\")){\n                        // 该笔订单真实的支付结果，需要依赖服务端的异步通知。\n                        paycallback.onFailure(ErrCode.CANCEL,\"pay cancel\");\n\n                    }else {\n\n                        paycallback.onFailure(ErrCode.FAILURE,\"pay fail\");\n                    }\n                    break;\n                }\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Alipay/src/main/java/com/bzai/gamesdk/plugin/alipay/pay/PayResult.java",
    "content": "package com.bzai.gamesdk.plugin.alipay.pay;\r\rimport android.text.TextUtils;\r\rimport java.util.Map;\r\rpublic class PayResult {\r\tprivate String resultStatus;\r\tprivate String result;\r\tprivate String memo;\r\r\tpublic PayResult(Map<String, String> rawResult) {\r\t\tif (rawResult == null) {\r\t\t\treturn;\r\t\t}\r\r\t\tfor (String key : rawResult.keySet()) {\r\t\t\tif (TextUtils.equals(key, \"resultStatus\")) {\r\t\t\t\tresultStatus = rawResult.get(key);\r\t\t\t} else if (TextUtils.equals(key, \"result\")) {\r\t\t\t\tresult = rawResult.get(key);\r\t\t\t} else if (TextUtils.equals(key, \"memo\")) {\r\t\t\t\tmemo = rawResult.get(key);\r\t\t\t}\r\t\t}\r\t}\r\r\t@Override\r\tpublic String toString() {\r\t\treturn \"resultStatus={\" + resultStatus + \"};memo={\" + memo\r\t\t\t\t+ \"};result={\" + result + \"}\";\r\t}\r\r\t/**\r\t * @return the resultStatus\r\t */\r\tpublic String getResultStatus() {\r\t\treturn resultStatus;\r\t}\r\r\t/**\r\t * @return the memo\r\t */\r\tpublic String getMemo() {\r\t\treturn memo;\r\t}\r\r\t/**\r\t * @return the result\r\t */\r\tpublic String getResult() {\r\t\treturn result;\r\t}\r}\r"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Alipay/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">GameSDK_Plugin_Alipay</string>\n</resources>\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Alipay/src/test/java/com/bzai/gamesdk/plugin/alipay/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdk.plugin.alipay;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Wechat/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Wechat/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDK_Utils')\n\n}\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Wechat/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Wechat/src/androidTest/java/com/bzai/gamesdk/plugin/wechat/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdk.plugin.wechat;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdk.plugin.wechat.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Wechat/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.plugin.wechat\" />\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Wechat/src/main/java/com/bzai/gamesdk/plugin/wechat/WechatPlugin.java",
    "content": "package com.bzai.gamesdk.plugin.wechat;\n\nimport android.content.Context;\n\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.parse.plugin.Plugin;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\nimport com.bzai.gamesdk.plugin.wechat.pay.WechatPay;\n\nimport java.util.Map;\n\n/**\n * Created by bzai on 2018/6/20.\n * <p>\n * Desc:\n *\n *  微信功能插件,方便后后续添加登录接口，支付(H5支付)接口，统计接口\n */\n\npublic class WechatPlugin extends Plugin {\n\n    private String TAG = \"WechatPlugin\";\n\n    @Override\n    protected synchronized void initPlugin() {\n        super.initPlugin();\n        LogUtils.d(TAG,\"init \" + getClass().getSimpleName());\n    }\n\n    /**\n     * 调用微信支付接口\n     */\n    public void wechatPay(Context context, Map<String,Object> payMap, CallBackListener callBackListener){\n        WechatPay.getInstance().pay(context,payMap,callBackListener);\n    }\n\n\n    /**\n     * 调用微信登录接口\n     */\n    public void wechatLogin(Context context, Map<String,Object> LoginMap, CallBackListener callBackListener){\n\n    }\n\n\n    /**\n     * 调用微信分享接口\n     */\n    public void wechatShare(Context context, Map<String,Object> ShareMap, CallBackListener callBackListener){\n\n    }\n\n    /**\n     * 根据当前的生命周期\n     * @param context\n     */\n    @Override\n    public void onResume(Context context) {\n        WechatPay.getInstance().onResume(context);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Wechat/src/main/java/com/bzai/gamesdk/plugin/wechat/login/WechatLogin.java",
    "content": "package com.bzai.gamesdk.plugin.wechat.login;\n\n\n/**\n * Created by bzai on 2018/6/21.\n * <p>\n * Desc:\n *\n *  封装微信登录\n */\n\npublic class WechatLogin {\n\n    public static String TAG = \"WechatPay\";\n\n    private volatile static WechatLogin INSTANCE;\n\n    private WechatLogin() {\n    }\n\n    public static WechatLogin getInstance() {\n        if (INSTANCE == null) {\n            synchronized (WechatLogin.class) {\n                if (INSTANCE == null) {\n                    INSTANCE = new WechatLogin();\n                }\n            }\n        }\n        return INSTANCE;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Wechat/src/main/java/com/bzai/gamesdk/plugin/wechat/pay/WechatPay.java",
    "content": "package com.bzai.gamesdk.plugin.wechat.pay;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\nimport com.tencent.mm.opensdk.modelpay.PayReq;\nimport com.tencent.mm.opensdk.openapi.IWXAPI;\nimport com.tencent.mm.opensdk.openapi.WXAPIFactory;\n\n\nimport java.util.Map;\n\n/**\n * Created by bzai on 2018/6/21.\n * <p>\n * Desc:\n *\n *   封装微信支付\n */\n\npublic class WechatPay {\n\n    public static String TAG = \"WechatPay\";\n\n    private volatile static WechatPay INSTANCE;\n\n    private WechatPay() {\n    }\n\n    public static WechatPay getInstance() {\n        if (INSTANCE == null) {\n            synchronized (WechatPay.class) {\n                if (INSTANCE == null) {\n                    INSTANCE = new WechatPay();\n                }\n            }\n        }\n        return INSTANCE;\n    }\n\n\n    /**\n     * 微信app支付\n     */\n    public void pay(Context context, Map<String,Object> payMap, CallBackListener callBackListener){\n\n    }\n\n\n    /**\n     * 处理微信没有回调的问题\n     * @param context\n     */\n    public void onResume(Context context) {\n        LogUtils.debug_d(TAG,\"onResume\");\n\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Plugin/GameSDK_Plugin_Wechat/src/test/java/com/bzai/gamesdk/plugin/wechat/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdk.plugin.wechat;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "GameSDK_Utils/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "GameSDK_Utils/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n}\n"
  },
  {
    "path": "GameSDK_Utils/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "GameSDK_Utils/src/androidTest/java/com/bzai/gamesdk/utils/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdk.utils;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdk.utils.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdk.utils\" />\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/cache/ApplicationCache.java",
    "content": "package com.bzai.gamesdk.common.utils_base.cache;\n\nimport android.app.Application;\nimport android.content.Context;\n\n/**\n * Created by bzai on 2018/7/16.\n * <p>\n * Desc:\n */\npublic class ApplicationCache {\n\n    private Application mAppContext;\n    public Context getApplication() {\n        return mAppContext;\n    }\n\n    /**\n     * 缓存全局的ApplicationContext\n     * @return\n     */\n    public Context getApplicationContext(){\n        return mAppContext.getApplicationContext();\n    }\n\n    /********************* 同步锁双重检测机制实现单例模式（懒加载）********************/\n\n    private volatile static ApplicationCache sCache;\n    private ApplicationCache(Application appContext) {\n        mAppContext = appContext;\n    }\n\n    public static ApplicationCache getInstance() {\n        if (sCache == null) {\n            throw new RuntimeException(\"get(Context) never called\");\n        }\n        return sCache;\n    }\n\n    public static ApplicationCache init(Application cxt) {\n        if (sCache == null) {\n            synchronized (ApplicationCache.class) {\n                if (sCache == null) {\n                    sCache = new ApplicationCache(cxt);\n                }\n            }\n        }\n        return sCache;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/config/ErrCode.java",
    "content": "package com.bzai.gamesdk.common.utils_base.config;\n\n/**\n * Created by bzai on 2018/4/9.\n *\n * 全局错误码类\n *\n */\n\npublic class ErrCode {\n\n    //--------------------- 公共(1000~1200) -------------------------\n\n    public static final int SUCCESS = 1000; //成功\n    public static final int FAILURE = 1001; //失败\n    public static final int CANCEL = 1002;  //取消\n    public static final int UNKONW = 1003;  //未知错误\n    public static final int PARAMS_ERROR = 1004;  //参数错误\n\n    public static final int NO_LOGIN = 1005;  //没有登录\n    public static final int NO_PAY_RESULT = 1006;  //渠道没有正确返回支付结果\n    public static final int NO_EXIT_DIALOG = 1007;  //渠道没有退出框\n    public static final int CHANNEL_LOGIN_CLOSE = 1008;  //后台关闭当前渠道登录\n    public static final int CHANNEL_PAY_CLOSE = 1009;  //后台关闭当前渠道支付\n\n\n    //---------------------网络(1200 ~ 1500 )-------------------------\n    public static final int NET_DISCONNET = 1201; //无网络连接\n    public static final int NET_ERROR = 1202; //访问网络异常\n    public static final int NET_TIME_OUT = 1203; //超时\n\n    public static final int NET_DATA_NULL = 1204; ////网络请求成功,但是数据为空\n    public static final int NET_DATA_ERROR = 1205; ////网络请求成功,但是数据类型错误。\n    public static final int NET_DATA_EXCEPTION = 1206; //网络请求成功,但是数据解析异常。\n\n\n    //--------------------- 针对渠道的错误码 -------------------------\n    public static final int CHANNEL_LOGIN_FAIL = 1501; //登录失败\n    public static final int CHANNEL_LOGIN_CANCEL = 1502; //登录取消\n\n    public static final int CHANNEL_SWITCH_ACCOUNT_FAIL = 1503; //切换账号失败\n    public static final int CHANNEL_SWITCH_ACCOUNT_CANCEL = 1504; //切换账号取消\n\n    public static final int CHANNEL_LOGOUT_FAIL = 1505; //注销失败\n    public static final int CHANNEL_LOGOUT_CANCEL = 1506; //注销取消\n\n\n\n\n\n\n\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/config/TypeConfig.java",
    "content": "package com.bzai.gamesdk.common.utils_base.config;\n\n/**\n * Created by bzai on 2018/7/12.\n * <p>\n * Desc:\n *\n *    定义基础的事件配置\n */\npublic class TypeConfig {\n\n    /**************************** 事件类型 *****************************/\n\n    //账号事件配置  (200 ~ 219) *************\n    public static final int LOGIN = 100;  //登录\n    public static final int SWITCHACCOUNT = 101;  //切换\n    public static final int BIND = 102;  //绑定\n    public static final int LOGOUT = 103;  //注销\n\n\n    //购买事件配置(220~239)\n    public static final int PAY = 150;  // 支付\n    public static final int SUBS = 151;  // 订阅\n\n\n    //是否支持该功能接口类型\n    public static final int FUNC_SWITCHACCOUNT = 250;  //切换\n    public static final int FUNC_LOGOUT = 251;  //注销\n    public static final int FUNC_SHOW_FLOATWINDOW = 252;  //显示浮窗\n    public static final int FUNC_DISMISS_FLOATWINDOW = 253;  //隐藏浮窗\n\n\n    /**************************** 事件方式配置 *****************************/\n\n\n    //登录方式配置(1~30)\n    public static final int LOGIN_AUTH = 1;  //三方授权登录(渠道登录)\n    public static final int LOGIN_ACCOUNT = 2;  //账号登录\n    public static final int LOGIN_PHONE = 3;  //手机登录\n    public static final int LOGIN_MAIL = 4;  //邮箱登录\n    public static final int LOGIN_TOKEN = 5;  //TOKEN登录\n    public static final int LOGIN_QUICK = 6;  //快速登录(随机账号登录/token登录)\n    public static final int LOGIN_GOOGLE = 7;  //GOOGLE授权登录\n    public static final int LOGIN_FACEBOOK = 8;  //facebook授权登录\n    public static final int LOGIN_LINE = 9;    //授权line登录\n    public static final int LOGIN_WECHAT = 10;  //微信授权登录\n    public static final int LOGIN_QQ = 11;      //QQ授权登录\n\n\n    //支付方式配置(31 ~60)\n    public static final int PAY_AUTH = 31;  //三方支付(渠道支付)\n    public static final int PAY_WECHAT = 32;  //微信支付\n    public static final int PAY_ALIPAY = 33;  //支付宝支付\n    public static final int PAY_UNIONPAY = 34;  //银联支付\n    public static final int PAY_GOOGLE = 35;  //google支付\n    public static final int PAY_PLATFORM = 36;  //自有平台币支付\n    public static final int PAY_REDEMPTION_CODE = 37;  //兑换码支付\n\n\n    //分享方式配置(61~90)\n    public static final int SHARE_WECHAT = 61;  //微信分享\n    public static final int SHARE_QQ = 62;  //微信分享\n    public static final int SHARE_SINA = 63;  //新浪微博分享\n    public static final int SHARE_FACEBOOK = 64;  //facebook分享\n    public static final int SHARE_GOOGLE = 65;  //google分享\n    public static final int SHARE_LINE = 66;  //line分享\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/DefaultDateTypeAdapter.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport java.lang.reflect.Type;\nimport java.sql.Timestamp;\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\nimport java.util.TimeZone;\n\n/**\n * This type adapter supports three subclasses of date: Date, Timestamp, and\n * java.sql.Date.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\nfinal class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {\n\n  // TODO: migrate to streaming adapter\n\n  private final DateFormat enUsFormat;\n  private final DateFormat localFormat;\n  private final DateFormat iso8601Format;\n\n  DefaultDateTypeAdapter() {\n    this(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US),\n        DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));\n  }\n\n  DefaultDateTypeAdapter(String datePattern) {\n    this(new SimpleDateFormat(datePattern, Locale.US), new SimpleDateFormat(datePattern));\n  }\n\n  DefaultDateTypeAdapter(int style) {\n    this(DateFormat.getDateInstance(style, Locale.US), DateFormat.getDateInstance(style));\n  }\n\n  public DefaultDateTypeAdapter(int dateStyle, int timeStyle) {\n    this(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US),\n        DateFormat.getDateTimeInstance(dateStyle, timeStyle));\n  }\n\n  DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) {\n    this.enUsFormat = enUsFormat;\n    this.localFormat = localFormat;\n    this.iso8601Format = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss'Z'\", Locale.US);\n    this.iso8601Format.setTimeZone(TimeZone.getTimeZone(\"UTC\"));\n  }\n\n  // These methods need to be synchronized since JDK DateFormat classes are not thread-safe\n  // See issue 162\n  public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {\n    synchronized (localFormat) {\n      String dateFormatAsString = enUsFormat.format(src);\n      return new JsonPrimitive(dateFormatAsString);\n    }\n  }\n\n  public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)\n      throws JsonParseException {\n    if (!(json instanceof JsonPrimitive)) {\n      throw new JsonParseException(\"The date should be a string value\");\n    }\n    Date date = deserializeToDate(json);\n    if (typeOfT == Date.class) {\n      return date;\n    } else if (typeOfT == Timestamp.class) {\n      return new Timestamp(date.getTime());\n    } else if (typeOfT == java.sql.Date.class) {\n      return new java.sql.Date(date.getTime());\n    } else {\n      throw new IllegalArgumentException(getClass() + \" cannot deserialize to \" + typeOfT);\n    }\n  }\n\n  private Date deserializeToDate(JsonElement json) {\n    synchronized (localFormat) {\n      try {\n        return localFormat.parse(json.getAsString());\n      } catch (ParseException ignored) {\n      }\n      try {\n        return enUsFormat.parse(json.getAsString());\n      } catch (ParseException ignored) {\n      }\n      try {\n        return iso8601Format.parse(json.getAsString());\n      } catch (ParseException e) {\n        throw new JsonSyntaxException(json.getAsString(), e);\n      }\n    }\n  }\n\n  @Override\n  public String toString() {\n    StringBuilder sb = new StringBuilder();\n    sb.append(DefaultDateTypeAdapter.class.getSimpleName());\n    sb.append('(').append(localFormat.getClass().getSimpleName()).append(')');\n    return sb.toString();\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/ExclusionStrategy.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\n/**\n * A strategy (or policy) definition that is used to decide whether or not a field or top-level\n * class should be serialized or deserialized as part of the JSON output/input. For serialization,\n * if the {@link #shouldSkipClass(Class)} method returns false then that class or field type\n * will not be part of the JSON output.  For deserialization, if {@link #shouldSkipClass(Class)}\n * returns false, then it will not be set as part of the Java object structure.\n *\n * <p>The following are a few examples that shows how you can use this exclusion mechanism.\n *\n * <p><strong>Exclude fields and objects based on a particular class type:</strong>\n * <pre class=\"code\">\n * private static class SpecificClassExclusionStrategy implements ExclusionStrategy {\n *   private final Class&lt;?&gt; excludedThisClass;\n *\n *   public SpecificClassExclusionStrategy(Class&lt;?&gt; excludedThisClass) {\n *     this.excludedThisClass = excludedThisClass;\n *   }\n *\n *   public boolean shouldSkipClass(Class&lt;?&gt; clazz) {\n *     return excludedThisClass.equals(clazz);\n *   }\n *\n *   public boolean shouldSkipField(FieldAttributes f) {\n *     return excludedThisClass.equals(f.getDeclaredClass());\n *   }\n * }\n * </pre>\n *\n * <p><strong>Excludes fields and objects based on a particular annotation:</strong>\n * <pre class=\"code\">\n * public &#64interface FooAnnotation {\n *   // some implementation here\n * }\n *\n * // Excludes any field (or class) that is tagged with an \"&#64FooAnnotation\"\n * private static class FooAnnotationExclusionStrategy implements ExclusionStrategy {\n *   public boolean shouldSkipClass(Class&lt;?&gt; clazz) {\n *     return clazz.getAnnotation(FooAnnotation.class) != null;\n *   }\n *\n *   public boolean shouldSkipField(FieldAttributes f) {\n *     return f.getAnnotation(FooAnnotation.class) != null;\n *   }\n * }\n * </pre>\n *\n * <p>Now if you want to configure {@code Gson} to use a user defined exclusion strategy, then\n * the {@code GsonBuilder} is required. The following is an example of how you can use the\n * {@code GsonBuilder} to configure Gson to use one of the above sample:\n * <pre class=\"code\">\n * ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);\n * Gson gson = new GsonBuilder()\n *     .setExclusionStrategies(excludeStrings)\n *     .create();\n * </pre>\n *\n * <p>For certain model classes, you may only want to serialize a field, but exclude it for\n * deserialization. To do that, you can write an {@code ExclusionStrategy} as per normal;\n * however, you would register it with the\n * {@link GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy)} method.\n * For example:\n * <pre class=\"code\">\n * ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);\n * Gson gson = new GsonBuilder()\n *     .addDeserializationExclusionStrategy(excludeStrings)\n *     .create();\n * </pre>\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n *\n * @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...)\n * @see GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy)\n * @see GsonBuilder#addSerializationExclusionStrategy(ExclusionStrategy)\n *\n * @since 1.4\n */\npublic interface ExclusionStrategy {\n\n  /**\n   * @param f the field object that is under test\n   * @return true if the field should be ignored; otherwise false\n   */\n  public boolean shouldSkipField(FieldAttributes f);\n\n  /**\n   * @param clazz the class object that is under test\n   * @return true if the class should be ignored; otherwise false\n   */\n  public boolean shouldSkipClass(Class<?> clazz);\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/FieldAttributes.java",
    "content": "/*\n * Copyright (C) 2009 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.$Gson$Preconditions;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Type;\nimport java.util.Arrays;\nimport java.util.Collection;\n\n/**\n * A data object that stores attributes of a field.\n *\n * <p>This class is immutable; therefore, it can be safely shared across threads.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n *\n * @since 1.4\n */\npublic final class FieldAttributes {\n  private final Field field;\n\n  /**\n   * Constructs a Field Attributes object from the {@code f}.\n   *\n   * @param f the field to pull attributes from\n   */\n  public FieldAttributes(Field f) {\n    $Gson$Preconditions.checkNotNull(f);\n    this.field = f;\n  }\n\n  /**\n   * @return the declaring class that contains this field\n   */\n  public Class<?> getDeclaringClass() {\n    return field.getDeclaringClass();\n  }\n\n  /**\n   * @return the name of the field\n   */\n  public String getName() {\n    return field.getName();\n  }\n\n  /**\n   * <p>For example, assume the following class definition:\n   * <pre class=\"code\">\n   * public class Foo {\n   *   private String bar;\n   *   private List&lt;String&gt; red;\n   * }\n   *\n   * Type listParmeterizedType = new TypeToken&lt;List&lt;String&gt;&gt;() {}.getType();\n   * </pre>\n   *\n   * <p>This method would return {@code String.class} for the {@code bar} field and\n   * {@code listParameterizedType} for the {@code red} field.\n   *\n   * @return the specific type declared for this field\n   */\n  public Type getDeclaredType() {\n    return field.getGenericType();\n  }\n\n  /**\n   * Returns the {@code Class} object that was declared for this field.\n   *\n   * <p>For example, assume the following class definition:\n   * <pre class=\"code\">\n   * public class Foo {\n   *   private String bar;\n   *   private List&lt;String&gt; red;\n   * }\n   * </pre>\n   *\n   * <p>This method would return {@code String.class} for the {@code bar} field and\n   * {@code List.class} for the {@code red} field.\n   *\n   * @return the specific class object that was declared for the field\n   */\n  public Class<?> getDeclaredClass() {\n    return field.getType();\n  }\n\n  /**\n   * Return the {@code T} annotation object from this field if it exist; otherwise returns\n   * {@code null}.\n   *\n   * @param annotation the class of the annotation that will be retrieved\n   * @return the annotation instance if it is bound to the field; otherwise {@code null}\n   */\n  public <T extends Annotation> T getAnnotation(Class<T> annotation) {\n    return field.getAnnotation(annotation);\n  }\n\n  /**\n   * Return the annotations that are present on this field.\n   *\n   * @return an array of all the annotations set on the field\n   * @since 1.4\n   */\n  public Collection<Annotation> getAnnotations() {\n    return Arrays.asList(field.getAnnotations());\n  }\n\n  /**\n   * Returns {@code true} if the field is defined with the {@code modifier}.\n   *\n   * <p>This method is meant to be called as:\n   * <pre class=\"code\">\n   * boolean hasPublicModifier = fieldAttribute.hasModifier(java.lang.reflect.Modifier.PUBLIC);\n   * </pre>\n   *\n   * @see java.lang.reflect.Modifier\n   */\n  public boolean hasModifier(int modifier) {\n    return (field.getModifiers() & modifier) != 0;\n  }\n\n  /**\n   * This is exposed internally only for the removing synthetic fields from the JSON output.\n   *\n   * @return true if the field is synthetic; otherwise false\n   * @throws IllegalAccessException\n   * @throws IllegalArgumentException\n   */\n  Object get(Object instance) throws IllegalAccessException {\n    return field.get(instance);\n  }\n\n  /**\n   * This is exposed internally only for the removing synthetic fields from the JSON output.\n   *\n   * @return true if the field is synthetic; otherwise false\n   */\n  boolean isSynthetic() {\n    return field.isSynthetic();\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/FieldNamingPolicy.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport java.lang.reflect.Field;\n\n/**\n * An enumeration that defines a few standard naming conventions for JSON field names.\n * This enumeration should be used in conjunction with {@link GsonBuilder}\n * to configure a {@link Gson} instance to properly translate Java field\n * names into the desired JSON field names.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic enum FieldNamingPolicy implements FieldNamingStrategy {\n\n  /**\n   * Using this naming policy with Gson will ensure that the field name is\n   * unchanged.\n   */\n  IDENTITY() {\n    public String translateName(Field f) {\n      return f.getName();\n    }\n  },\n\n  /**\n   * Using this naming policy with Gson will ensure that the first \"letter\" of the Java\n   * field name is capitalized when serialized to its JSON form.\n   *\n   * <p>Here's a few examples of the form \"Java Field Name\" ---> \"JSON Field Name\":</p>\n   * <ul>\n   *   <li>someFieldName ---> SomeFieldName</li>\n   *   <li>_someFieldName ---> _SomeFieldName</li>\n   * </ul>\n   */\n  UPPER_CAMEL_CASE() {\n    public String translateName(Field f) {\n      return upperCaseFirstLetter(f.getName());\n    }\n  },\n\n  /**\n   * Using this naming policy with Gson will ensure that the first \"letter\" of the Java\n   * field name is capitalized when serialized to its JSON form and the words will be\n   * separated by a space.\n   *\n   * <p>Here's a few examples of the form \"Java Field Name\" ---> \"JSON Field Name\":</p>\n   * <ul>\n   *   <li>someFieldName ---> Some Field Name</li>\n   *   <li>_someFieldName ---> _Some Field Name</li>\n   * </ul>\n   *\n   * @since 1.4\n   */\n  UPPER_CAMEL_CASE_WITH_SPACES() {\n    public String translateName(Field f) {\n      return upperCaseFirstLetter(separateCamelCase(f.getName(), \" \"));\n    }\n  },\n\n  /**\n   * Using this naming policy with Gson will modify the Java Field name from its camel cased\n   * form to a lower case field name where each word is separated by an underscore (_).\n   *\n   * <p>Here's a few examples of the form \"Java Field Name\" ---> \"JSON Field Name\":</p>\n   * <ul>\n   *   <li>someFieldName ---> some_field_name</li>\n   *   <li>_someFieldName ---> _some_field_name</li>\n   *   <li>aStringField ---> a_string_field</li>\n   *   <li>aURL ---> a_u_r_l</li>\n   * </ul>\n   */\n  LOWER_CASE_WITH_UNDERSCORES() {\n    public String translateName(Field f) {\n      return separateCamelCase(f.getName(), \"_\").toLowerCase();\n    }\n  },\n\n  /**\n   * Using this naming policy with Gson will modify the Java Field name from its camel cased\n   * form to a lower case field name where each word is separated by a dash (-).\n   *\n   * <p>Here's a few examples of the form \"Java Field Name\" ---> \"JSON Field Name\":</p>\n   * <ul>\n   *   <li>someFieldName ---> some-field-name</li>\n   *   <li>_someFieldName ---> _some-field-name</li>\n   *   <li>aStringField ---> a-string-field</li>\n   *   <li>aURL ---> a-u-r-l</li>\n   * </ul>\n   * Using dashes in JavaScript is not recommended since dash is also used for a minus sign in\n   * expressions. This requires that a field named with dashes is always accessed as a quoted\n   * property like {@code myobject['my-field']}. Accessing it as an object field\n   * {@code myobject.my-field} will result in an unintended javascript expression.\n   * @since 1.4\n   */\n  LOWER_CASE_WITH_DASHES() {\n    public String translateName(Field f) {\n      return separateCamelCase(f.getName(), \"-\").toLowerCase();\n    }\n  };\n\n  /**\n   * Converts the field name that uses camel-case define word separation into\n   * separate words that are separated by the provided {@code separatorString}.\n   */\n  private static String separateCamelCase(String name, String separator) {\n    StringBuilder translation = new StringBuilder();\n    for (int i = 0; i < name.length(); i++) {\n      char character = name.charAt(i);\n      if (Character.isUpperCase(character) && translation.length() != 0) {\n        translation.append(separator);\n      }\n      translation.append(character);\n    }\n    return translation.toString();\n  }\n\n  /**\n   * Ensures the JSON field names begins with an upper case letter.\n   */\n  private static String upperCaseFirstLetter(String name) {\n    StringBuilder fieldNameBuilder = new StringBuilder();\n    int index = 0;\n    char firstCharacter = name.charAt(index);\n\n    while (index < name.length() - 1) {\n      if (Character.isLetter(firstCharacter)) {\n        break;\n      }\n\n      fieldNameBuilder.append(firstCharacter);\n      firstCharacter = name.charAt(++index);\n    }\n\n    if (index == name.length()) {\n      return fieldNameBuilder.toString();\n    }\n\n    if (!Character.isUpperCase(firstCharacter)) {\n      String modifiedTarget = modifyString(Character.toUpperCase(firstCharacter), name, ++index);\n      return fieldNameBuilder.append(modifiedTarget).toString();\n    } else {\n      return name;\n    }\n  }\n\n  private static String modifyString(char firstCharacter, String srcString, int indexOfSubstring) {\n    return (indexOfSubstring < srcString.length())\n        ? firstCharacter + srcString.substring(indexOfSubstring)\n        : String.valueOf(firstCharacter);\n  }\n}"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/FieldNamingStrategy.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport java.lang.reflect.Field;\n\n/**\n * A mechanism for providing custom field naming in Gson.  This allows the client code to translate\n * field names into a particular convention that is not supported as a normal Java field\n * declaration rules.  For example, Java does not support \"-\" characters in a field name.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n * @since 1.3\n */\npublic interface FieldNamingStrategy {\n\n  /**\n   * Translates the field name into its JSON field name representation.\n   *\n   * @param f the field object that we are translating\n   * @return the translated field name.\n   * @since 1.3\n   */\n  public String translateName(Field f);\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/Gson.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations.Expose;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations.Since;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.ConstructorConstructor;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.Excluder;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.Primitives;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.Streams;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.ArrayTypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.CollectionTypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.DateTypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.JsonTreeReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.JsonTreeWriter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.MapTypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.ObjectTypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.ReflectiveTypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.SqlDateTypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.TimeTypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.TypeAdapters;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.MalformedJsonException;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.io.Writer;\nimport java.lang.reflect.Type;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * This is the main class for using Gson. Gson is typically used by first constructing a\n * Gson instance and then invoking {@link #toJson(Object)} or {@link #fromJson(String, Class)}\n * methods on it.\n *\n * <p>You can create a Gson instance by invoking {@code new Gson()} if the default configuration\n * is all you need. You can also use {@link GsonBuilder} to build a Gson instance with various\n * configuration options such as versioning support, pretty printing, custom\n * {@link JsonSerializer}s, {@link JsonDeserializer}s, and {@link InstanceCreator}s.</p>\n *\n * <p>Here is an example of how Gson is used for a simple Class:\n *\n * <pre>\n * Gson gson = new Gson(); // Or use new GsonBuilder().create();\n * MyType target = new MyType();\n * String json = gson.toJson(target); // serializes target to Json\n * MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2\n * </pre></p>\n *\n * <p>If the object that your are serializing/deserializing is a {@code ParameterizedType}\n * (i.e. contains at least one type parameter and may be an array) then you must use the\n * {@link #toJson(Object, Type)} or {@link #fromJson(String, Type)} method.  Here is an\n * example for serializing and deserialing a {@code ParameterizedType}:\n *\n * <pre>\n * Type listType = new TypeToken&lt;List&lt;String&gt;&gt;() {}.getType();\n * List&lt;String&gt; target = new LinkedList&lt;String&gt;();\n * target.add(\"blah\");\n *\n * Gson gson = new Gson();\n * String json = gson.toJson(target, listType);\n * List&lt;String&gt; target2 = gson.fromJson(json, listType);\n * </pre></p>\n *\n * <p>See the <a href=\"https://sites.google.com/site/gson/gson-user-guide\">Gson User Guide</a>\n * for a more complete set of examples.</p>\n *\n * @see TypeToken\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n * @author Jesse Wilson\n */\npublic final class Gson {\n  static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;\n\n  private static final String JSON_NON_EXECUTABLE_PREFIX = \")]}'\\n\";\n\n  /**\n   * This thread local guards against reentrant calls to getAdapter(). In\n   * certain object graphs, creating an adapter for a type may recursively\n   * require an adapter for the same type! Without intervention, the recursive\n   * lookup would stack overflow. We cheat by returning a proxy type adapter.\n   * The proxy is wired up once the initial adapter has been created.\n   */\n  private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls\n      = new ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>>() {\n    @Override\n    protected Map<TypeToken<?>, FutureTypeAdapter<?>> initialValue() {\n      return new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();\n    }\n  };\n\n  private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache\n      = Collections.synchronizedMap(new HashMap<TypeToken<?>, TypeAdapter<?>>());\n\n  private final List<TypeAdapterFactory> factories;\n  private final ConstructorConstructor constructorConstructor;\n\n  private final boolean serializeNulls;\n  private final boolean htmlSafe;\n  private final boolean generateNonExecutableJson;\n  private final boolean prettyPrinting;\n\n  final JsonDeserializationContext deserializationContext = new JsonDeserializationContext() {\n    @SuppressWarnings(\"unchecked\")\n\tpublic <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException {\n      return (T) fromJson(json, typeOfT);\n    }\n  };\n\n  final JsonSerializationContext serializationContext = new JsonSerializationContext() {\n    public JsonElement serialize(Object src) {\n      return toJsonTree(src);\n    }\n    public JsonElement serialize(Object src, Type typeOfSrc) {\n      return toJsonTree(src, typeOfSrc);\n    }\n  };\n\n  /**\n   * Constructs a Gson object with default configuration. The default configuration has the\n   * following settings:\n   * <ul>\n   *   <li>The JSON generated by <code>toJson</code> methods is in compact representation. This\n   *   means that all the unneeded white-space is removed. You can change this behavior with\n   *   {@link GsonBuilder#setPrettyPrinting()}. </li>\n   *   <li>The generated JSON omits all the fields that are null. Note that nulls in arrays are\n   *   kept as is since an array is an ordered list. Moreover, if a field is not null, but its\n   *   generated JSON is empty, the field is kept. You can configure Gson to serialize null values\n   *   by setting {@link GsonBuilder#serializeNulls()}.</li>\n   *   <li>Gson provides default serialization and deserialization for Enums, {@link Map},\n   *   {@link java.net.URL}, {@link java.net.URI}, {@link java.util.Locale}, {@link java.util.Date},\n   *   {@link BigDecimal}, and {@link BigInteger} classes. If you would prefer\n   *   to change the default representation, you can do so by registering a type adapter through\n   *   {@link GsonBuilder#registerTypeAdapter(Type, Object)}. </li>\n   *   <li>The default Date format is same as {@link java.text.DateFormat#DEFAULT}. This format\n   *   ignores the millisecond portion of the date during serialization. You can change\n   *   this by invoking {@link GsonBuilder#setDateFormat(int)} or\n   *   {@link GsonBuilder#setDateFormat(String)}. </li>\n   *   <li>By default, Gson ignores the {@link Expose} annotation.\n   *   You can enable Gson to serialize/deserialize only those fields marked with this annotation\n   *   through {@link GsonBuilder#excludeFieldsWithoutExposeAnnotation()}. </li>\n   *   <li>By default, Gson ignores the {@link Since} annotation. You\n   *   can enable Gson to use this annotation through {@link GsonBuilder#setVersion(double)}.</li>\n   *   <li>The default field naming policy for the output Json is same as in Java. So, a Java class\n   *   field <code>versionNumber</code> will be output as <code>&quot;versionNumber@quot;</code> in\n   *   Json. The same rules are applied for mapping incoming Json to the Java classes. You can\n   *   change this policy through {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}.</li>\n   *   <li>By default, Gson excludes <code>transient</code> or <code>static</code> fields from\n   *   consideration for serialization and deserialization. You can change this behavior through\n   *   {@link GsonBuilder#excludeFieldsWithModifiers(int...)}.</li>\n   * </ul>\n   */\n  public Gson() {\n    this(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY,\n        Collections.<Type, InstanceCreator<?>>emptyMap(), false, false, DEFAULT_JSON_NON_EXECUTABLE,\n        true, false, false, LongSerializationPolicy.DEFAULT,\n        Collections.<TypeAdapterFactory>emptyList());\n  }\n\n  Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingPolicy,\n       final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,\n       boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,\n       boolean prettyPrinting, boolean serializeSpecialFloatingPointValues,\n       LongSerializationPolicy longSerializationPolicy,\n       List<TypeAdapterFactory> typeAdapterFactories) {\n    this.constructorConstructor = new ConstructorConstructor(instanceCreators);\n    this.serializeNulls = serializeNulls;\n    this.generateNonExecutableJson = generateNonExecutableGson;\n    this.htmlSafe = htmlSafe;\n    this.prettyPrinting = prettyPrinting;\n\n    List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();\n\n    // built-in type adapters that cannot be overridden\n    factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);\n    factories.add(ObjectTypeAdapter.FACTORY);\n\n    // user's type adapters\n    factories.addAll(typeAdapterFactories);\n\n    // type adapters for basic platform types\n    factories.add(TypeAdapters.STRING_FACTORY);\n    factories.add(TypeAdapters.INTEGER_FACTORY);\n    factories.add(TypeAdapters.BOOLEAN_FACTORY);\n    factories.add(TypeAdapters.BYTE_FACTORY);\n    factories.add(TypeAdapters.SHORT_FACTORY);\n    factories.add(TypeAdapters.newFactory(long.class, Long.class,\n            longAdapter(longSerializationPolicy)));\n    factories.add(TypeAdapters.newFactory(double.class, Double.class,\n            doubleAdapter(serializeSpecialFloatingPointValues)));\n    factories.add(TypeAdapters.newFactory(float.class, Float.class,\n            floatAdapter(serializeSpecialFloatingPointValues)));\n    factories.add(TypeAdapters.NUMBER_FACTORY);\n    factories.add(TypeAdapters.CHARACTER_FACTORY);\n    factories.add(TypeAdapters.STRING_BUILDER_FACTORY);\n    factories.add(TypeAdapters.STRING_BUFFER_FACTORY);\n    factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));\n    factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));\n    factories.add(TypeAdapters.URL_FACTORY);\n    factories.add(TypeAdapters.URI_FACTORY);\n    factories.add(TypeAdapters.UUID_FACTORY);\n    factories.add(TypeAdapters.LOCALE_FACTORY);\n    factories.add(TypeAdapters.INET_ADDRESS_FACTORY);\n    factories.add(TypeAdapters.BIT_SET_FACTORY);\n    factories.add(DateTypeAdapter.FACTORY);\n    factories.add(TypeAdapters.CALENDAR_FACTORY);\n    factories.add(TimeTypeAdapter.FACTORY);\n    factories.add(SqlDateTypeAdapter.FACTORY);\n    factories.add(TypeAdapters.TIMESTAMP_FACTORY);\n    factories.add(ArrayTypeAdapter.FACTORY);\n    factories.add(TypeAdapters.ENUM_FACTORY);\n    factories.add(TypeAdapters.CLASS_FACTORY);\n\n    // the excluder must precede all adapters that handle user-defined types\n    factories.add(excluder);\n\n    // type adapters for composite and user-defined types\n    factories.add(new CollectionTypeAdapterFactory(constructorConstructor));\n    factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));\n    factories.add(new ReflectiveTypeAdapterFactory(\n        constructorConstructor, fieldNamingPolicy, excluder));\n\n    this.factories = Collections.unmodifiableList(factories);\n  }\n\n  private TypeAdapter<Number> doubleAdapter(boolean serializeSpecialFloatingPointValues) {\n    if (serializeSpecialFloatingPointValues) {\n      return TypeAdapters.DOUBLE;\n    }\n    return new TypeAdapter<Number>() {\n      @Override\n      public Double read(JsonReader in) throws IOException {\n        if (in.peek() == JsonToken.NULL) {\n          in.nextNull();\n          return null;\n        }\n        return in.nextDouble();\n      }\n      @Override\n      public void write(JsonWriter out, Number value) throws IOException {\n        if (value == null) {\n          out.nullValue();\n          return;\n        }\n        double doubleValue = value.doubleValue();\n        checkValidFloatingPoint(doubleValue);\n        out.value(value);\n      }\n    };\n  }\n\n  private TypeAdapter<Number> floatAdapter(boolean serializeSpecialFloatingPointValues) {\n    if (serializeSpecialFloatingPointValues) {\n      return TypeAdapters.FLOAT;\n    }\n    return new TypeAdapter<Number>() {\n      @Override\n      public Float read(JsonReader in) throws IOException {\n        if (in.peek() == JsonToken.NULL) {\n          in.nextNull();\n          return null;\n        }\n        return (float) in.nextDouble();\n      }\n      @Override\n      public void write(JsonWriter out, Number value) throws IOException {\n        if (value == null) {\n          out.nullValue();\n          return;\n        }\n        float floatValue = value.floatValue();\n        checkValidFloatingPoint(floatValue);\n        out.value(value);\n      }\n    };\n  }\n\n  private void checkValidFloatingPoint(double value) {\n    if (Double.isNaN(value) || Double.isInfinite(value)) {\n      throw new IllegalArgumentException(value\n          + \" is not a valid double value as per JSON specification. To override this\"\n          + \" behavior, use GsonBuilder.serializeSpecialDoubleValues() method.\");\n    }\n  }\n\n  private TypeAdapter<Number> longAdapter(LongSerializationPolicy longSerializationPolicy) {\n    if (longSerializationPolicy == LongSerializationPolicy.DEFAULT) {\n      return TypeAdapters.LONG;\n    }\n    return new TypeAdapter<Number>() {\n      @Override\n      public Number read(JsonReader in) throws IOException {\n        if (in.peek() == JsonToken.NULL) {\n          in.nextNull();\n          return null;\n        }\n        return in.nextLong();\n      }\n      @Override\n      public void write(JsonWriter out, Number value) throws IOException {\n        if (value == null) {\n          out.nullValue();\n          return;\n        }\n        out.value(value.toString());\n      }\n    };\n  }\n\n  /**\n   * Returns the type adapter for {@code} type.\n   *\n   * @throws IllegalArgumentException if this GSON cannot serialize and\n   *     deserialize {@code type}.\n   */\n  @SuppressWarnings(\"unchecked\")\n  public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {\n    TypeAdapter<?> cached = typeTokenCache.get(type);\n    if (cached != null) {\n      return (TypeAdapter<T>) cached;\n    }\n\n    Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();\n    // the key and value type parameters always agree\n    FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);\n    if (ongoingCall != null) {\n      return ongoingCall;\n    }\n\n    FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();\n    threadCalls.put(type, call);\n    try {\n      for (TypeAdapterFactory factory : factories) {\n        TypeAdapter<T> candidate = factory.create(this, type);\n        if (candidate != null) {\n          call.setDelegate(candidate);\n          typeTokenCache.put(type, candidate);\n          return candidate;\n        }\n      }\n      throw new IllegalArgumentException(\"GSON cannot handle \" + type);\n    } finally {\n      threadCalls.remove(type);\n    }\n  }\n\n  /**\n   * This method is used to get an alternate type adapter for the specified type. This is used\n   * to access a type adapter that is overridden by a {@link TypeAdapterFactory} that you\n   * may have registered. This features is typically used when you want to register a type\n   * adapter that does a little bit of work but then delegates further processing to the Gson\n   * default type adapter. Here is an example:\n   * <p>Let's say we want to write a type adapter that counts the number of objects being read\n   *  from or written to JSON. We can achieve this by writing a type adapter factory that uses\n   *  the <code>getDelegateAdapter</code> method:\n   *  <pre> {@code\n   *  class StatsTypeAdapterFactory implements TypeAdapterFactory {\n   *    public int numReads = 0;\n   *    public int numWrites = 0;\n   *    public &lt;T&gt; TypeAdapter&lt;T&gt; create(Gson gson, TypeToken&lt;T&gt; type) {\n   *      final TypeAdapter&lt;T&gt; delegate = gson.getDelegateAdapter(this, type);\n   *      return new TypeAdapter&lt;T&gt;() {\n   *        public void write(JsonWriter out, T value) throws IOException {\n   *          ++numWrites;\n   *          delegate.write(out, value);\n   *        }\n   *        public T read(JsonReader in) throws IOException {\n   *          ++numReads;\n   *          return delegate.read(in);\n   *        }\n   *      };\n   *    }\n   *  }\n   *  } </pre>\n   *  This factory can now be used like this:\n   *  <pre> {@code\n   *  StatsTypeAdapterFactory stats = new StatsTypeAdapterFactory();\n   *  Gson gson = new GsonBuilder().registerTypeAdapterFactory(stats).create();\n   *  // Call gson.toJson() and fromJson methods on objects\n   *  System.out.println(\"Num JSON reads\" + stats.numReads);\n   *  System.out.println(\"Num JSON writes\" + stats.numWrites);\n   *  }</pre>\n   *  Note that since you can not override type adapter factories for String and Java primitive\n   *  types, our stats factory will not count the number of String or primitives that will be\n   *  read or written. \n   * @param skipPast The type adapter factory that needs to be skipped while searching for\n   *   a matching type adapter. In most cases, you should just pass <i>this</i> (the type adapter\n   *   factory from where {@link #getDelegateAdapter} method is being invoked).\n   * @param type Type for which the delegate adapter is being searched for.\n   *\n   * @since 2.2\n   */\n  public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken<T> type) {\n    boolean skipPastFound = false;\n\n    for (TypeAdapterFactory factory : factories) {\n      if (!skipPastFound) {\n        if (factory == skipPast) {\n          skipPastFound = true;\n        }\n        continue;\n      }\n\n      TypeAdapter<T> candidate = factory.create(this, type);\n      if (candidate != null) {\n        return candidate;\n      }\n    }\n    throw new IllegalArgumentException(\"GSON cannot serialize \" + type);\n  }\n\n  /**\n   * Returns the type adapter for {@code} type.\n   *\n   * @throws IllegalArgumentException if this GSON cannot serialize and\n   *     deserialize {@code type}.\n   */\n  public <T> TypeAdapter<T> getAdapter(Class<T> type) {\n    return getAdapter(TypeToken.get(type));\n  }\n\n  /**\n   * This method serializes the specified object into its equivalent representation as a tree of\n   * {@link JsonElement}s. This method should be used when the specified object is not a generic\n   * type. This method uses {@link Class#getClass()} to get the type for the specified object, but\n   * the {@code getClass()} loses the generic type information because of the Type Erasure feature\n   * of Java. Note that this method works fine if the any of the object fields are of generic type,\n   * just the object itself should not be of a generic type. If the object is of generic type, use\n   * {@link #toJsonTree(Object, Type)} instead.\n   *\n   * @param src the object for which Json representation is to be created setting for Gson\n   * @return Json representation of {@code src}.\n   * @since 1.4\n   */\n  public JsonElement toJsonTree(Object src) {\n    if (src == null) {\n      return JsonNull.INSTANCE;\n    }\n    return toJsonTree(src, src.getClass());\n  }\n\n  /**\n   * This method serializes the specified object, including those of generic types, into its\n   * equivalent representation as a tree of {@link JsonElement}s. This method must be used if the\n   * specified object is a generic type. For non-generic objects, use {@link #toJsonTree(Object)}\n   * instead.\n   *\n   * @param src the object for which JSON representation is to be created\n   * @param typeOfSrc The specific genericized type of src. You can obtain\n   * this type by using the {@link TypeToken} class. For example,\n   * to get the type for {@code Collection<Foo>}, you should use:\n   * <pre>\n   * Type typeOfSrc = new TypeToken&lt;Collection&lt;Foo&gt;&gt;(){}.getType();\n   * </pre>\n   * @return Json representation of {@code src}\n   * @since 1.4\n   */\n  public JsonElement toJsonTree(Object src, Type typeOfSrc) {\n    JsonTreeWriter writer = new JsonTreeWriter();\n    toJson(src, typeOfSrc, writer);\n    return writer.get();\n  }\n\n  /**\n   * This method serializes the specified object into its equivalent Json representation.\n   * This method should be used when the specified object is not a generic type. This method uses\n   * {@link Class#getClass()} to get the type for the specified object, but the\n   * {@code getClass()} loses the generic type information because of the Type Erasure feature\n   * of Java. Note that this method works fine if the any of the object fields are of generic type,\n   * just the object itself should not be of a generic type. If the object is of generic type, use\n   * {@link #toJson(Object, Type)} instead. If you want to write out the object to a\n   * {@link Writer}, use {@link #toJson(Object, Appendable)} instead.\n   *\n   * @param src the object for which Json representation is to be created setting for Gson\n   * @return Json representation of {@code src}.\n   */\n  public String toJson(Object src) {\n    if (src == null) {\n      return toJson(JsonNull.INSTANCE);\n    }\n    return toJson(src, src.getClass());\n  }\n\n  /**\n   * This method serializes the specified object, including those of generic types, into its\n   * equivalent Json representation. This method must be used if the specified object is a generic\n   * type. For non-generic objects, use {@link #toJson(Object)} instead. If you want to write out\n   * the object to a {@link Appendable}, use {@link #toJson(Object, Type, Appendable)} instead.\n   *\n   * @param src the object for which JSON representation is to be created\n   * @param typeOfSrc The specific genericized type of src. You can obtain\n   * this type by using the {@link TypeToken} class. For example,\n   * to get the type for {@code Collection<Foo>}, you should use:\n   * <pre>\n   * Type typeOfSrc = new TypeToken&lt;Collection&lt;Foo&gt;&gt;(){}.getType();\n   * </pre>\n   * @return Json representation of {@code src}\n   */\n  public String toJson(Object src, Type typeOfSrc) {\n    StringWriter writer = new StringWriter();\n    toJson(src, typeOfSrc, writer);\n    return writer.toString();\n  }\n\n  /**\n   * This method serializes the specified object into its equivalent Json representation.\n   * This method should be used when the specified object is not a generic type. This method uses\n   * {@link Class#getClass()} to get the type for the specified object, but the\n   * {@code getClass()} loses the generic type information because of the Type Erasure feature\n   * of Java. Note that this method works fine if the any of the object fields are of generic type,\n   * just the object itself should not be of a generic type. If the object is of generic type, use\n   * {@link #toJson(Object, Type, Appendable)} instead.\n   *\n   * @param src the object for which Json representation is to be created setting for Gson\n   * @param writer Writer to which the Json representation needs to be written\n   * @throws JsonIOException if there was a problem writing to the writer\n   * @since 1.2\n   */\n  public void toJson(Object src, Appendable writer) throws JsonIOException {\n    if (src != null) {\n      toJson(src, src.getClass(), writer);\n    } else {\n      toJson(JsonNull.INSTANCE, writer);\n    }\n  }\n\n  /**\n   * This method serializes the specified object, including those of generic types, into its\n   * equivalent Json representation. This method must be used if the specified object is a generic\n   * type. For non-generic objects, use {@link #toJson(Object, Appendable)} instead.\n   *\n   * @param src the object for which JSON representation is to be created\n   * @param typeOfSrc The specific genericized type of src. You can obtain\n   * this type by using the {@link TypeToken} class. For example,\n   * to get the type for {@code Collection<Foo>}, you should use:\n   * <pre>\n   * Type typeOfSrc = new TypeToken&lt;Collection&lt;Foo&gt;&gt;(){}.getType();\n   * </pre>\n   * @param writer Writer to which the Json representation of src needs to be written.\n   * @throws JsonIOException if there was a problem writing to the writer\n   * @since 1.2\n   */\n  public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException {\n    try {\n      JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));\n      toJson(src, typeOfSrc, jsonWriter);\n    } catch (IOException e) {\n      throw new JsonIOException(e);\n    }\n  }\n\n  /**\n   * Writes the JSON representation of {@code src} of type {@code typeOfSrc} to\n   * {@code writer}.\n   * @throws JsonIOException if there was a problem writing to the writer\n   */\n  @SuppressWarnings(\"unchecked\")\n  public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {\n    TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc));\n    boolean oldLenient = writer.isLenient();\n    writer.setLenient(true);\n    boolean oldHtmlSafe = writer.isHtmlSafe();\n    writer.setHtmlSafe(htmlSafe);\n    boolean oldSerializeNulls = writer.getSerializeNulls();\n    writer.setSerializeNulls(serializeNulls);\n    try {\n      ((TypeAdapter<Object>) adapter).write(writer, src);\n    } catch (IOException e) {\n      throw new JsonIOException(e);\n    } finally {\n      writer.setLenient(oldLenient);\n      writer.setHtmlSafe(oldHtmlSafe);\n      writer.setSerializeNulls(oldSerializeNulls);\n    }\n  }\n\n  /**\n   * Converts a tree of {@link JsonElement}s into its equivalent JSON representation.\n   *\n   * @param jsonElement root of a tree of {@link JsonElement}s\n   * @return JSON String representation of the tree\n   * @since 1.4\n   */\n  public String toJson(JsonElement jsonElement) {\n    StringWriter writer = new StringWriter();\n    toJson(jsonElement, writer);\n    return writer.toString();\n  }\n\n  /**\n   * Writes out the equivalent JSON for a tree of {@link JsonElement}s.\n   *\n   * @param jsonElement root of a tree of {@link JsonElement}s\n   * @param writer Writer to which the Json representation needs to be written\n   * @throws JsonIOException if there was a problem writing to the writer\n   * @since 1.4\n   */\n  public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException {\n    try {\n      JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));\n      toJson(jsonElement, jsonWriter);\n    } catch (IOException e) {\n      throw new RuntimeException(e);\n    }\n  }\n\n  /**\n   * Returns a new JSON writer configured for this GSON and with the non-execute\n   * prefix if that is configured.\n   */\n  private JsonWriter newJsonWriter(Writer writer) throws IOException {\n    if (generateNonExecutableJson) {\n      writer.write(JSON_NON_EXECUTABLE_PREFIX);\n    }\n    JsonWriter jsonWriter = new JsonWriter(writer);\n    if (prettyPrinting) {\n      jsonWriter.setIndent(\"  \");\n    }\n    jsonWriter.setSerializeNulls(serializeNulls);\n    return jsonWriter;\n  }\n\n  /**\n   * Writes the JSON for {@code jsonElement} to {@code writer}.\n   * @throws JsonIOException if there was a problem writing to the writer\n   */\n  public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException {\n    boolean oldLenient = writer.isLenient();\n    writer.setLenient(true);\n    boolean oldHtmlSafe = writer.isHtmlSafe();\n    writer.setHtmlSafe(htmlSafe);\n    boolean oldSerializeNulls = writer.getSerializeNulls();\n    writer.setSerializeNulls(serializeNulls);\n    try {\n      Streams.write(jsonElement, writer);\n    } catch (IOException e) {\n      throw new JsonIOException(e);\n    } finally {\n      writer.setLenient(oldLenient);\n      writer.setHtmlSafe(oldHtmlSafe);\n      writer.setSerializeNulls(oldSerializeNulls);\n    }\n  }\n\n  /**\n   * This method deserializes the specified Json into an object of the specified class. It is not\n   * suitable to use if the specified class is a generic type since it will not have the generic\n   * type information because of the Type Erasure feature of Java. Therefore, this method should not\n   * be used if the desired type is a generic type. Note that this method works fine if the any of\n   * the fields of the specified object are generics, just the object itself should not be a\n   * generic type. For the cases when the object is of generic type, invoke\n   * {@link #fromJson(String, Type)}. If you have the Json in a {@link Reader} instead of\n   * a String, use {@link #fromJson(Reader, Class)} instead.\n   *\n   * @param <T> the type of the desired object\n   * @param json the string from which the object is to be deserialized\n   * @param classOfT the class of T\n   * @return an object of type T from the string\n   * @throws JsonSyntaxException if json is not a valid representation for an object of type\n   * classOfT\n   */\n  public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {\n    Object object = fromJson(json, (Type) classOfT);\n    return Primitives.wrap(classOfT).cast(object);\n  }\n\n  /**\n   * This method deserializes the specified Json into an object of the specified type. This method\n   * is useful if the specified object is a generic type. For non-generic objects, use\n   * {@link #fromJson(String, Class)} instead. If you have the Json in a {@link Reader} instead of\n   * a String, use {@link #fromJson(Reader, Type)} instead.\n   *\n   * @param <T> the type of the desired object\n   * @param json the string from which the object is to be deserialized\n   * @param typeOfT The specific genericized type of src. You can obtain this type by using the\n   * {@link TypeToken} class. For example, to get the type for\n   * {@code Collection<Foo>}, you should use:\n   * <pre>\n   * Type typeOfT = new TypeToken&lt;Collection&lt;Foo&gt;&gt;(){}.getType();\n   * </pre>\n   * @return an object of type T from the string\n   * @throws JsonParseException if json is not a valid representation for an object of type typeOfT\n   * @throws JsonSyntaxException if json is not a valid representation for an object of type\n   */\n  @SuppressWarnings(\"unchecked\")\n  public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {\n    if (json == null) {\n      return null;\n    }\n    StringReader reader = new StringReader(json);\n    T target = (T) fromJson(reader, typeOfT);\n    return target;\n  }\n\n  /**\n   * This method deserializes the Json read from the specified reader into an object of the\n   * specified class. It is not suitable to use if the specified class is a generic type since it\n   * will not have the generic type information because of the Type Erasure feature of Java.\n   * Therefore, this method should not be used if the desired type is a generic type. Note that\n   * this method works fine if the any of the fields of the specified object are generics, just the\n   * object itself should not be a generic type. For the cases when the object is of generic type,\n   * invoke {@link #fromJson(Reader, Type)}. If you have the Json in a String form instead of a\n   * {@link Reader}, use {@link #fromJson(String, Class)} instead.\n   *\n   * @param <T> the type of the desired object\n   * @param json the reader producing the Json from which the object is to be deserialized.\n   * @param classOfT the class of T\n   * @return an object of type T from the string\n   * @throws JsonIOException if there was a problem reading from the Reader\n   * @throws JsonSyntaxException if json is not a valid representation for an object of type\n   * @since 1.2\n   */\n  public <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException, JsonIOException {\n    JsonReader jsonReader = new JsonReader(json);\n    Object object = fromJson(jsonReader, classOfT);\n    assertFullConsumption(object, jsonReader);\n    return Primitives.wrap(classOfT).cast(object);\n  }\n\n  /**\n   * This method deserializes the Json read from the specified reader into an object of the\n   * specified type. This method is useful if the specified object is a generic type. For\n   * non-generic objects, use {@link #fromJson(Reader, Class)} instead. If you have the Json in a\n   * String form instead of a {@link Reader}, use {@link #fromJson(String, Type)} instead.\n   *\n   * @param <T> the type of the desired object\n   * @param json the reader producing Json from which the object is to be deserialized\n   * @param typeOfT The specific genericized type of src. You can obtain this type by using the\n   * {@link TypeToken} class. For example, to get the type for\n   * {@code Collection<Foo>}, you should use:\n   * <pre>\n   * Type typeOfT = new TypeToken&lt;Collection&lt;Foo&gt;&gt;(){}.getType();\n   * </pre>\n   * @return an object of type T from the json\n   * @throws JsonIOException if there was a problem reading from the Reader\n   * @throws JsonSyntaxException if json is not a valid representation for an object of type\n   * @since 1.2\n   */\n  @SuppressWarnings(\"unchecked\")\n  public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {\n    JsonReader jsonReader = new JsonReader(json);\n    T object = (T) fromJson(jsonReader, typeOfT);\n    assertFullConsumption(object, jsonReader);\n    return object;\n  }\n\n  private static void assertFullConsumption(Object obj, JsonReader reader) {\n    try {\n      if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) {\n        throw new JsonIOException(\"JSON document was not fully consumed.\");\n      }\n    } catch (MalformedJsonException e) {\n      throw new JsonSyntaxException(e);\n    } catch (IOException e) {\n      throw new JsonIOException(e);\n    }\n  }\n\n  /**\n   * Reads the next JSON value from {@code reader} and convert it to an object\n   * of type {@code typeOfT}.\n   * Since Type is not parameterized by T, this method is type unsafe and should be used carefully\n   *\n   * @throws JsonIOException if there was a problem writing to the Reader\n   * @throws JsonSyntaxException if json is not a valid representation for an object of type\n   */\n  @SuppressWarnings(\"unchecked\")\n  public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {\n    boolean isEmpty = true;\n    boolean oldLenient = reader.isLenient();\n    reader.setLenient(true);\n    try {\n      reader.peek();\n      isEmpty = false;\n      TypeAdapter<T> typeAdapter = (TypeAdapter<T>) getAdapter(TypeToken.get(typeOfT));\n      return typeAdapter.read(reader);\n    } catch (EOFException e) {\n      /*\n       * For compatibility with JSON 1.5 and earlier, we return null for empty\n       * documents instead of throwing.\n       */\n      if (isEmpty) {\n        return null;\n      }\n      throw new JsonSyntaxException(e);\n    } catch (IllegalStateException e) {\n      throw new JsonSyntaxException(e);\n    } catch (IOException e) {\n      // TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException\n      throw new JsonSyntaxException(e);\n    } finally {\n      reader.setLenient(oldLenient);\n    }\n  }\n\n  /**\n   * This method deserializes the Json read from the specified parse tree into an object of the\n   * specified type. It is not suitable to use if the specified class is a generic type since it\n   * will not have the generic type information because of the Type Erasure feature of Java.\n   * Therefore, this method should not be used if the desired type is a generic type. Note that\n   * this method works fine if the any of the fields of the specified object are generics, just the\n   * object itself should not be a generic type. For the cases when the object is of generic type,\n   * invoke {@link #fromJson(JsonElement, Type)}.\n   * @param <T> the type of the desired object\n   * @param json the root of the parse tree of {@link JsonElement}s from which the object is to\n   * be deserialized\n   * @param classOfT The class of T\n   * @return an object of type T from the json\n   * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT\n   * @since 1.3\n   */\n  public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {\n    Object object = fromJson(json, (Type) classOfT);\n    return Primitives.wrap(classOfT).cast(object);\n  }\n\n  /**\n   * This method deserializes the Json read from the specified parse tree into an object of the\n   * specified type. This method is useful if the specified object is a generic type. For\n   * non-generic objects, use {@link #fromJson(JsonElement, Class)} instead.\n   *\n   * @param <T> the type of the desired object\n   * @param json the root of the parse tree of {@link JsonElement}s from which the object is to\n   * be deserialized\n   * @param typeOfT The specific genericized type of src. You can obtain this type by using the\n   * {@link TypeToken} class. For example, to get the type for\n   * {@code Collection<Foo>}, you should use:\n   * <pre>\n   * Type typeOfT = new TypeToken&lt;Collection&lt;Foo&gt;&gt;(){}.getType();\n   * </pre>\n   * @return an object of type T from the json\n   * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT\n   * @since 1.3\n   */\n  @SuppressWarnings(\"unchecked\")\n  public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException {\n    if (json == null) {\n      return null;\n    }\n    return (T) fromJson(new JsonTreeReader(json), typeOfT);\n  }\n\n  static class FutureTypeAdapter<T> extends TypeAdapter<T> {\n    private TypeAdapter<T> delegate;\n\n    public void setDelegate(TypeAdapter<T> typeAdapter) {\n      if (delegate != null) {\n        throw new AssertionError();\n      }\n      delegate = typeAdapter;\n    }\n\n    @Override\n    public T read(JsonReader in) throws IOException {\n      if (delegate == null) {\n        throw new IllegalStateException();\n      }\n      return delegate.read(in);\n    }\n\n    @Override\n    public void write(JsonWriter out, T value) throws IOException {\n      if (delegate == null) {\n        throw new IllegalStateException();\n      }\n      delegate.write(out, value);\n    }\n  }\n\n  @Override\n  public String toString() {\n  \tStringBuilder sb = new StringBuilder(\"{\")\n  \t    .append(\"serializeNulls:\").append(serializeNulls)\n  \t    .append(\"factories:\").append(factories)\n        .append(\",instanceCreators:\").append(constructorConstructor)\n        .append(\"}\");\n  \treturn sb.toString();\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/GsonBuilder.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations.Expose;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.$Gson$Preconditions;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.Excluder;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.TypeAdapters;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\n\nimport java.lang.reflect.Type;\nimport java.sql.Timestamp;\nimport java.text.DateFormat;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * <p>Use this builder to construct a {@link Gson} instance when you need to set configuration\n * options other than the default. For {@link Gson} with default configuration, it is simpler to\n * use {@code new Gson()}. {@code GsonBuilder} is best used by creating it, and then invoking its\n * various configuration methods, and finally calling create.</p>\n *\n * <p>The following is an example shows how to use the {@code GsonBuilder} to construct a Gson\n * instance:\n *\n * <pre>\n * Gson gson = new GsonBuilder()\n *     .registerTypeAdapter(Id.class, new IdTypeAdapter())\n *     .enableComplexMapKeySerialization()\n *     .serializeNulls()\n *     .setDateFormat(DateFormat.LONG)\n *     .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)\n *     .setPrettyPrinting()\n *     .setVersion(1.0)\n *     .create();\n * </pre></p>\n *\n * <p>NOTES:\n * <ul>\n * <li> the order of invocation of configuration methods does not matter.</li>\n * <li> The default serialization of {@link Date} and its subclasses in Gson does\n *  not contain time-zone information. So, if you are using date/time instances,\n *  use {@code GsonBuilder} and its {@code setDateFormat} methods.</li>\n *  </ul>\n * </p>\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n * @author Jesse Wilson\n */\npublic final class GsonBuilder {\n  private Excluder excluder = Excluder.DEFAULT;\n  private LongSerializationPolicy longSerializationPolicy = LongSerializationPolicy.DEFAULT;\n  private FieldNamingStrategy fieldNamingPolicy = FieldNamingPolicy.IDENTITY;\n  private final Map<Type, InstanceCreator<?>> instanceCreators\n      = new HashMap<Type, InstanceCreator<?>>();\n  private final List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();\n  /** tree-style hierarchy factories. These come after factories for backwards compatibility. */\n  private final List<TypeAdapterFactory> hierarchyFactories = new ArrayList<TypeAdapterFactory>();\n  private boolean serializeNulls;\n  private String datePattern;\n  private int dateStyle = DateFormat.DEFAULT;\n  private int timeStyle = DateFormat.DEFAULT;\n  private boolean complexMapKeySerialization;\n  private boolean serializeSpecialFloatingPointValues;\n  private boolean escapeHtmlChars = true;\n  private boolean prettyPrinting;\n  private boolean generateNonExecutableJson;\n\n  /**\n   * Creates a GsonBuilder instance that can be used to build Gson with various configuration\n   * settings. GsonBuilder follows the builder pattern, and it is typically used by first\n   * invoking various configuration methods to set desired options, and finally calling\n   * {@link #create()}.\n   */\n  public GsonBuilder() {\n  }\n\n  /**\n   * Configures Gson to enable versioning support.\n   *\n   * @param ignoreVersionsAfter any field or type marked with a version higher than this value\n   * are ignored during serialization or deserialization.\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   */\n  public GsonBuilder setVersion(double ignoreVersionsAfter) {\n    excluder = excluder.withVersion(ignoreVersionsAfter);\n    return this;\n  }\n\n  /**\n   * Configures Gson to excludes all class fields that have the specified modifiers. By default,\n   * Gson will exclude all fields marked transient or static. This method will override that\n   * behavior.\n   *\n   * @param modifiers the field modifiers. You must use the modifiers specified in the\n   * {@link java.lang.reflect.Modifier} class. For example,\n   * {@link java.lang.reflect.Modifier#TRANSIENT},\n   * {@link java.lang.reflect.Modifier#STATIC}.\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   */\n  public GsonBuilder excludeFieldsWithModifiers(int... modifiers) {\n    excluder = excluder.withModifiers(modifiers);\n    return this;\n  }\n\n  /**\n   * Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some\n   * special text. This prevents attacks from third-party sites through script sourcing. See\n   * <a href=\"http://code.google.com/p/google-gson/issues/detail?id=42\">Gson Issue 42</a>\n   * for details.\n   *\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.3\n   */\n  public GsonBuilder generateNonExecutableJson() {\n    this.generateNonExecutableJson = true;\n    return this;\n  }\n\n  /**\n   * Configures Gson to exclude all fields from consideration for serialization or deserialization\n   * that do not have the {@link Expose} annotation.\n   *\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   */\n  public GsonBuilder excludeFieldsWithoutExposeAnnotation() {\n    excluder = excluder.excludeFieldsWithoutExposeAnnotation();\n    return this;\n  }\n\n  /**\n   * Configure Gson to serialize null fields. By default, Gson omits all fields that are null\n   * during serialization.\n   *\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.2\n   */\n  public GsonBuilder serializeNulls() {\n    this.serializeNulls = true;\n    return this;\n  }\n\n  /**\n   * Enabling this feature will only change the serialized form if the map key is\n   * a complex type (i.e. non-primitive) in its <strong>serialized</strong> JSON\n   * form. The default implementation of map serialization uses {@code toString()}\n   * on the key; however, when this is called then one of the following cases\n   * apply:\n   *\n   * <h3>Maps as JSON objects</h3>\n   * For this case, assume that a type adapter is registered to serialize and\n   * deserialize some {@code Point} class, which contains an x and y coordinate,\n   * to/from the JSON Primitive string value {@code \"(x,y)\"}. The Java map would\n   * then be serialized as a {@link JsonObject}.\n   *\n   * <p>Below is an example:\n   * <pre>  {@code\n   *   Gson gson = new GsonBuilder()\n   *       .register(Point.class, new MyPointTypeAdapter())\n   *       .enableComplexMapKeySerialization()\n   *       .create();\n   *\n   *   Map<Point, String> original = new LinkedHashMap<Point, String>();\n   *   original.put(new Point(5, 6), \"a\");\n   *   original.put(new Point(8, 8), \"b\");\n   *   System.out.println(gson.toJson(original, type));\n   * }</pre>\n   * The above code prints this JSON object:<pre>  {@code\n   *   {\n   *     \"(5,6)\": \"a\",\n   *     \"(8,8)\": \"b\"\n   *   }\n   * }</pre>\n   *\n   * <h3>Maps as JSON arrays</h3>\n   * For this case, assume that a type adapter was NOT registered for some\n   * {@code Point} class, but rather the default Gson serialization is applied.\n   * In this case, some {@code new Point(2,3)} would serialize as {@code\n   * {\"x\":2,\"y\":5}}.\n   *\n   * <p>Given the assumption above, a {@code Map<Point, String>} will be\n   * serialize as an array of arrays (can be viewed as an entry set of pairs).\n   *\n   * <p>Below is an example of serializing complex types as JSON arrays:\n   * <pre> {@code\n   *   Gson gson = new GsonBuilder()\n   *       .enableComplexMapKeySerialization()\n   *       .create();\n   *\n   *   Map<Point, String> original = new LinkedHashMap<Point, String>();\n   *   original.put(new Point(5, 6), \"a\");\n   *   original.put(new Point(8, 8), \"b\");\n   *   System.out.println(gson.toJson(original, type));\n   * }\n   *\n   * The JSON output would look as follows:\n   * <pre>   {@code\n   *   [\n   *     [\n   *       {\n   *         \"x\": 5,\n   *         \"y\": 6\n   *       },\n   *       \"a\"\n   *     ],\n   *     [\n   *       {\n   *         \"x\": 8,\n   *         \"y\": 8\n   *       },\n   *       \"b\"\n   *     ]\n   *   ]\n   * }</pre>\n   *\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.7\n   */\n  public GsonBuilder enableComplexMapKeySerialization() {\n    complexMapKeySerialization = true;\n    return this;\n  }\n\n  /**\n   * Configures Gson to exclude inner classes during serialization.\n   *\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.3\n   */\n  public GsonBuilder disableInnerClassSerialization() {\n    excluder = excluder.disableInnerClassSerialization();\n    return this;\n  }\n\n  /**\n   * Configures Gson to apply a specific serialization policy for {@code Long} and {@code long}\n   * objects.\n   *\n   * @param serializationPolicy the particular policy to use for serializing longs.\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.3\n   */\n  public GsonBuilder setLongSerializationPolicy(LongSerializationPolicy serializationPolicy) {\n    this.longSerializationPolicy = serializationPolicy;\n    return this;\n  }\n\n  /**\n   * Configures Gson to apply a specific naming policy to an object's field during serialization\n   * and deserialization.\n   *\n   * @param namingConvention the JSON field naming convention to use for serialization and\n   * deserialization.\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   */\n  public GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention) {\n    this.fieldNamingPolicy = namingConvention;\n    return this;\n  }\n\n  /**\n   * Configures Gson to apply a specific naming policy strategy to an object's field during\n   * serialization and deserialization.\n   *\n   * @param fieldNamingStrategy the actual naming strategy to apply to the fields\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.3\n   */\n  public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) {\n    this.fieldNamingPolicy = fieldNamingStrategy;\n    return this;\n  }\n\n  /**\n   * Configures Gson to apply a set of exclusion strategies during both serialization and\n   * deserialization. Each of the {@code strategies} will be applied as a disjunction rule.\n   * This means that if one of the {@code strategies} suggests that a field (or class) should be\n   * skipped then that field (or object) is skipped during serializaiton/deserialization.\n   *\n   * @param strategies the set of strategy object to apply during object (de)serialization.\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.4\n   */\n  public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {\n    for (ExclusionStrategy strategy : strategies) {\n      excluder = excluder.withExclusionStrategy(strategy, true, true);\n    }\n    return this;\n  }\n\n  /**\n   * Configures Gson to apply the passed in exclusion strategy during serialization.\n   * If this method is invoked numerous times with different exclusion strategy objects\n   * then the exclusion strategies that were added will be applied as a disjunction rule.\n   * This means that if one of the added exclusion strategies suggests that a field (or\n   * class) should be skipped then that field (or object) is skipped during its\n   * serialization.\n   *\n   * @param strategy an exclusion strategy to apply during serialization.\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.7\n   */\n  public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy) {\n    excluder = excluder.withExclusionStrategy(strategy, true, false);\n    return this;\n  }\n\n  /**\n   * Configures Gson to apply the passed in exclusion strategy during deserialization.\n   * If this method is invoked numerous times with different exclusion strategy objects\n   * then the exclusion strategies that were added will be applied as a disjunction rule.\n   * This means that if one of the added exclusion strategies suggests that a field (or\n   * class) should be skipped then that field (or object) is skipped during its\n   * deserialization.\n   *\n   * @param strategy an exclusion strategy to apply during deserialization.\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.7\n   */\n  public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy) {\n    excluder = excluder.withExclusionStrategy(strategy, false, true);\n    return this;\n  }\n\n  /**\n   * Configures Gson to output Json that fits in a page for pretty printing. This option only\n   * affects Json serialization.\n   *\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   */\n  public GsonBuilder setPrettyPrinting() {\n    prettyPrinting = true;\n    return this;\n  }\n\n  /**\n   * By default, Gson escapes HTML characters such as &lt; &gt; etc. Use this option to configure\n   * Gson to pass-through HTML characters as is.\n   *\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.3\n   */\n  public GsonBuilder disableHtmlEscaping() {\n    this.escapeHtmlChars = false;\n    return this;\n  }\n\n  /**\n   * Configures Gson to serialize {@code Date} objects according to the pattern provided. You can\n   * call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation\n   * will be used to decide the serialization format.\n   *\n   * <p>The date format will be used to serialize and deserialize {@link Date}, {@link\n   * Timestamp} and {@link java.sql.Date}.\n   *\n   * <p>Note that this pattern must abide by the convention provided by {@code SimpleDateFormat}\n   * class. See the documentation in {@link java.text.SimpleDateFormat} for more information on\n   * valid date and time patterns.</p>\n   *\n   * @param pattern the pattern that dates will be serialized/deserialized to/from\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.2\n   */\n  public GsonBuilder setDateFormat(String pattern) {\n    // TODO(Joel): Make this fail fast if it is an invalid date format\n    this.datePattern = pattern;\n    return this;\n  }\n\n  /**\n   * Configures Gson to to serialize {@code Date} objects according to the style value provided.\n   * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last\n   * invocation will be used to decide the serialization format.\n   *\n   * <p>Note that this style value should be one of the predefined constants in the\n   * {@code DateFormat} class. See the documentation in {@link DateFormat} for more\n   * information on the valid style constants.</p>\n   *\n   * @param style the predefined date style that date objects will be serialized/deserialized\n   * to/from\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.2\n   */\n  public GsonBuilder setDateFormat(int style) {\n    this.dateStyle = style;\n    this.datePattern = null;\n    return this;\n  }\n\n  /**\n   * Configures Gson to to serialize {@code Date} objects according to the style value provided.\n   * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last\n   * invocation will be used to decide the serialization format.\n   *\n   * <p>Note that this style value should be one of the predefined constants in the\n   * {@code DateFormat} class. See the documentation in {@link DateFormat} for more\n   * information on the valid style constants.</p>\n   *\n   * @param dateStyle the predefined date style that date objects will be serialized/deserialized\n   * to/from\n   * @param timeStyle the predefined style for the time portion of the date objects\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.2\n   */\n  public GsonBuilder setDateFormat(int dateStyle, int timeStyle) {\n    this.dateStyle = dateStyle;\n    this.timeStyle = timeStyle;\n    this.datePattern = null;\n    return this;\n  }\n\n  /**\n   * Configures Gson for custom serialization or deserialization. This method combines the\n   * registration of an {@link TypeAdapter}, {@link InstanceCreator}, {@link JsonSerializer}, and a\n   * {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter} implements\n   * all the required interfaces for custom serialization with Gson. If a type adapter was\n   * previously registered for the specified {@code type}, it is overwritten.\n   *\n   * <p>This registers the type specified and no other types: you must manually register related\n   * types! For example, applications registering {@code boolean.class} should also register {@code\n   * Boolean.class}.\n   *\n   * @param type the type definition for the type adapter being registered\n   * @param typeAdapter This object must implement at least one of the {@link TypeAdapter},\n   * {@link InstanceCreator}, {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   */\n  @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n  public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {\n    $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>\n        || typeAdapter instanceof JsonDeserializer<?>\n        || typeAdapter instanceof InstanceCreator<?>\n        || typeAdapter instanceof TypeAdapter<?>);\n    if (typeAdapter instanceof InstanceCreator<?>) {\n      instanceCreators.put(type, (InstanceCreator) typeAdapter);\n    }\n    if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) {\n      TypeToken<?> typeToken = TypeToken.get(type);\n      factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter));\n    }\n    if (typeAdapter instanceof TypeAdapter<?>) {\n      factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter));\n    }\n    return this;\n  }\n\n  /**\n   * Register a factory for type adapters. Registering a factory is useful when the type\n   * adapter needs to be configured based on the type of the field being processed. Gson\n   * is designed to handle a large number of factories, so you should consider registering\n   * them to be at par with registering an individual type adapter.\n   *\n   * @since 2.1\n   */\n  public GsonBuilder registerTypeAdapterFactory(TypeAdapterFactory factory) {\n    factories.add(factory);\n    return this;\n  }\n\n  /**\n   * Configures Gson for custom serialization or deserialization for an inheritance type hierarchy.\n   * This method combines the registration of a {@link TypeAdapter}, {@link JsonSerializer} and\n   * a {@link JsonDeserializer}. If a type adapter was previously registered for the specified\n   * type hierarchy, it is overridden. If a type adapter is registered for a specific type in\n   * the type hierarchy, it will be invoked instead of the one registered for the type hierarchy.\n   *\n   * @param baseType the class definition for the type adapter being registered for the base class\n   *        or interface\n   * @param typeAdapter This object must implement at least one of {@link TypeAdapter},\n   *        {@link JsonSerializer} or {@link JsonDeserializer} interfaces.\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.7\n   */\n  @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n  public GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) {\n    $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>\n        || typeAdapter instanceof JsonDeserializer<?>\n        || typeAdapter instanceof TypeAdapter<?>);\n    if (typeAdapter instanceof JsonDeserializer || typeAdapter instanceof JsonSerializer) {\n      hierarchyFactories.add(0,\n          TreeTypeAdapter.newTypeHierarchyFactory(baseType, typeAdapter));\n    }\n    if (typeAdapter instanceof TypeAdapter<?>) {\n      factories.add(TypeAdapters.newTypeHierarchyFactory(baseType, (TypeAdapter)typeAdapter));\n    }\n    return this;\n  }\n\n  /**\n   * Section 2.4 of <a href=\"http://www.ietf.org/rfc/rfc4627.txt\">JSON specification</a> disallows\n   * special double values (NaN, Infinity, -Infinity). However,\n   * <a href=\"http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf\">Javascript\n   * specification</a> (see section 4.3.20, 4.3.22, 4.3.23) allows these values as valid Javascript\n   * values. Moreover, most JavaScript engines will accept these special values in JSON without\n   * problem. So, at a practical level, it makes sense to accept these values as valid JSON even\n   * though JSON specification disallows them.\n   *\n   * <p>Gson always accepts these special values during deserialization. However, it outputs\n   * strictly compliant JSON. Hence, if it encounters a float value {@link Float#NaN},\n   * {@link Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY}, or a double value\n   * {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}, it\n   * will throw an {@link IllegalArgumentException}. This method provides a way to override the\n   * default behavior when you know that the JSON receiver will be able to handle these special\n   * values.\n   *\n   * @return a reference to this {@code GsonBuilder} object to fulfill the \"Builder\" pattern\n   * @since 1.3\n   */\n  public GsonBuilder serializeSpecialFloatingPointValues() {\n    this.serializeSpecialFloatingPointValues = true;\n    return this;\n  }\n\n  /**\n   * Creates a {@link Gson} instance based on the current configuration. This method is free of\n   * side-effects to this {@code GsonBuilder} instance and hence can be called multiple times.\n   *\n   * @return an instance of Gson configured with the options currently set in this builder\n   */\n  public Gson create() {\n    List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();\n    factories.addAll(this.factories);\n    Collections.reverse(factories);\n    factories.addAll(this.hierarchyFactories);\n    addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, factories);\n\n    return new Gson(excluder, fieldNamingPolicy, instanceCreators,\n        serializeNulls, complexMapKeySerialization,\n        generateNonExecutableJson, escapeHtmlChars, prettyPrinting,\n        serializeSpecialFloatingPointValues, longSerializationPolicy, factories);\n  }\n\n  private void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle,\n                                      List<TypeAdapterFactory> factories) {\n    DefaultDateTypeAdapter dateTypeAdapter;\n    if (datePattern != null && !\"\".equals(datePattern.trim())) {\n      dateTypeAdapter = new DefaultDateTypeAdapter(datePattern);\n    } else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) {\n      dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle, timeStyle);\n    } else {\n      return;\n    }\n\n    factories.add(TreeTypeAdapter.newFactory(TypeToken.get(Date.class), dateTypeAdapter));\n    factories.add(TreeTypeAdapter.newFactory(TypeToken.get(Timestamp.class), dateTypeAdapter));\n    factories.add(TreeTypeAdapter.newFactory(TypeToken.get(java.sql.Date.class), dateTypeAdapter));\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/InstanceCreator.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport java.lang.reflect.Type;\n\n/**\n * This interface is implemented to create instances of a class that does not define a no-args\n * constructor. If you can modify the class, you should instead add a private, or public\n * no-args constructor. However, that is not possible for library classes, such as JDK classes, or\n * a third-party library that you do not have source-code of. In such cases, you should define an\n * instance creator for the class. Implementations of this interface should be registered with\n * {@link GsonBuilder#registerTypeAdapter(Type, Object)} method before Gson will be able to use\n * them.\n * <p>Let us look at an example where defining an InstanceCreator might be useful. The\n * {@code Id} class defined below does not have a default no-args constructor.</p>\n *\n * <pre>\n * public class Id&lt;T&gt; {\n *   private final Class&lt;T&gt; clazz;\n *   private final long value;\n *   public Id(Class&lt;T&gt; clazz, long value) {\n *     this.clazz = clazz;\n *     this.value = value;\n *   }\n * }\n * </pre>\n *\n * <p>If Gson encounters an object of type {@code Id} during deserialization, it will throw an\n * exception. The easiest way to solve this problem will be to add a (public or private) no-args\n * constructor as follows:</p>\n *\n * <pre>\n * private Id() {\n *   this(Object.class, 0L);\n * }\n * </pre>\n *\n * <p>However, let us assume that the developer does not have access to the source-code of the\n * {@code Id} class, or does not want to define a no-args constructor for it. The developer\n * can solve this problem by defining an {@code InstanceCreator} for {@code Id}:</p>\n *\n * <pre>\n * class IdInstanceCreator implements InstanceCreator&lt;Id&gt; {\n *   public Id createInstance(Type type) {\n *     return new Id(Object.class, 0L);\n *   }\n * }\n * </pre>\n *\n * <p>Note that it does not matter what the fields of the created instance contain since Gson will\n * overwrite them with the deserialized values specified in Json. You should also ensure that a\n * <i>new</i> object is returned, not a common object since its fields will be overwritten.\n * The developer will need to register {@code IdInstanceCreator} with Gson as follows:</p>\n *\n * <pre>\n * Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdInstanceCreator()).create();\n * </pre>\n *\n * @param <T> the type of object that will be created by this implementation.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic interface InstanceCreator<T> {\n\n  /**\n   * Gson invokes this call-back method during deserialization to create an instance of the\n   * specified type. The fields of the returned instance are overwritten with the data present\n   * in the Json. Since the prior contents of the object are destroyed and overwritten, do not\n   * return an instance that is useful elsewhere. In particular, do not return a common instance,\n   * always use {@code new} to create a new instance.\n   *\n   * @param type the parameterized T represented as a {@link Type}.\n   * @return a default object instance of type T.\n   */\n  public T createInstance(Type type);\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonArray.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\n/**\n * A class representing an array type in Json. An array is a list of {@link JsonElement}s each of\n * which can be of a different type. This is an ordered list, meaning that the order in which\n * elements are added is preserved.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic final class JsonArray extends JsonElement implements Iterable<JsonElement> {\n  private final List<JsonElement> elements;\n\n  /**\n   * Creates an empty JsonArray.\n   */\n  public JsonArray() {\n    elements = new ArrayList<JsonElement>();\n  }\n\n  /**\n   * Adds the specified element to self.\n   *\n   * @param element the element that needs to be added to the array.\n   */\n  public void add(JsonElement element) {\n    if (element == null) {\n      element = JsonNull.INSTANCE;\n    }\n    elements.add(element);\n  }\n\n  /**\n   * Adds all the elements of the specified array to self.\n   *\n   * @param array the array whose elements need to be added to the array.\n   */\n  public void addAll(JsonArray array) {\n    elements.addAll(array.elements);\n  }\n\n  /**\n   * Returns the number of elements in the array.\n   *\n   * @return the number of elements in the array.\n   */\n  public int size() {\n    return elements.size();\n  }\n\n  /**\n   * Returns an iterator to navigate the elemetns of the array. Since the array is an ordered list,\n   * the iterator navigates the elements in the order they were inserted.\n   *\n   * @return an iterator to navigate the elements of the array.\n   */\n  public Iterator<JsonElement> iterator() {\n    return elements.iterator();\n  }\n\n  /**\n   * Returns the ith element of the array.\n   *\n   * @param i the index of the element that is being sought.\n   * @return the element present at the ith index.\n   * @throws IndexOutOfBoundsException if i is negative or greater than or equal to the\n   * {@link #size()} of the array.\n   */\n  public JsonElement get(int i) {\n    return elements.get(i);\n  }\n\n  /**\n   * convenience method to get this array as a {@link Number} if it contains a single element.\n   *\n   * @return get this element as a number if it is single element array.\n   * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and\n   * is not a valid Number.\n   * @throws IllegalStateException if the array has more than one element.\n   */\n  @Override\n  public Number getAsNumber() {\n    if (elements.size() == 1) {\n      return elements.get(0).getAsNumber();\n    }\n    throw new IllegalStateException();\n  }\n\n  /**\n   * convenience method to get this array as a {@link String} if it contains a single element.\n   *\n   * @return get this element as a String if it is single element array.\n   * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and\n   * is not a valid String.\n   * @throws IllegalStateException if the array has more than one element.\n   */\n  @Override\n  public String getAsString() {\n    if (elements.size() == 1) {\n      return elements.get(0).getAsString();\n    }\n    throw new IllegalStateException();\n  }\n\n  /**\n   * convenience method to get this array as a double if it contains a single element.\n   *\n   * @return get this element as a double if it is single element array.\n   * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and\n   * is not a valid double.\n   * @throws IllegalStateException if the array has more than one element.\n   */\n  @Override\n  public double getAsDouble() {\n    if (elements.size() == 1) {\n      return elements.get(0).getAsDouble();\n    }\n    throw new IllegalStateException();\n  }\n\n  /**\n   * convenience method to get this array as a {@link BigDecimal} if it contains a single element.\n   *\n   * @return get this element as a {@link BigDecimal} if it is single element array.\n   * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}.\n   * @throws NumberFormatException if the element at index 0 is not a valid {@link BigDecimal}.\n   * @throws IllegalStateException if the array has more than one element.\n   * @since 1.2\n   */\n  @Override\n  public BigDecimal getAsBigDecimal() {\n    if (elements.size() == 1) {\n      return elements.get(0).getAsBigDecimal();\n    }\n    throw new IllegalStateException();\n  }\n\n  /**\n   * convenience method to get this array as a {@link BigInteger} if it contains a single element.\n   *\n   * @return get this element as a {@link BigInteger} if it is single element array.\n   * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}.\n   * @throws NumberFormatException if the element at index 0 is not a valid {@link BigInteger}.\n   * @throws IllegalStateException if the array has more than one element.\n   * @since 1.2\n   */\n  @Override\n  public BigInteger getAsBigInteger() {\n    if (elements.size() == 1) {\n      return elements.get(0).getAsBigInteger();\n    }\n    throw new IllegalStateException();\n  }\n\n  /**\n   * convenience method to get this array as a float if it contains a single element.\n   *\n   * @return get this element as a float if it is single element array.\n   * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and\n   * is not a valid float.\n   * @throws IllegalStateException if the array has more than one element.\n   */\n  @Override\n  public float getAsFloat() {\n    if (elements.size() == 1) {\n      return elements.get(0).getAsFloat();\n    }\n    throw new IllegalStateException();\n  }\n\n  /**\n   * convenience method to get this array as a long if it contains a single element.\n   *\n   * @return get this element as a long if it is single element array.\n   * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and\n   * is not a valid long.\n   * @throws IllegalStateException if the array has more than one element.\n   */\n  @Override\n  public long getAsLong() {\n    if (elements.size() == 1) {\n      return elements.get(0).getAsLong();\n    }\n    throw new IllegalStateException();\n  }\n\n  /**\n   * convenience method to get this array as an integer if it contains a single element.\n   *\n   * @return get this element as an integer if it is single element array.\n   * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and\n   * is not a valid integer.\n   * @throws IllegalStateException if the array has more than one element.\n   */\n  @Override\n  public int getAsInt() {\n    if (elements.size() == 1) {\n      return elements.get(0).getAsInt();\n    }\n    throw new IllegalStateException();\n  }\n\n  @Override\n  public byte getAsByte() {\n    if (elements.size() == 1) {\n      return elements.get(0).getAsByte();\n    }\n    throw new IllegalStateException();\n  }\n\n  @Override\n  public char getAsCharacter() {\n    if (elements.size() == 1) {\n      return elements.get(0).getAsCharacter();\n    }\n    throw new IllegalStateException();\n  }\n\n  /**\n   * convenience method to get this array as a primitive short if it contains a single element.\n   *\n   * @return get this element as a primitive short if it is single element array.\n   * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and\n   * is not a valid short.\n   * @throws IllegalStateException if the array has more than one element.\n   */\n  @Override\n  public short getAsShort() {\n    if (elements.size() == 1) {\n      return elements.get(0).getAsShort();\n    }\n    throw new IllegalStateException();\n  }\n\n  /**\n   * convenience method to get this array as a boolean if it contains a single element.\n   *\n   * @return get this element as a boolean if it is single element array.\n   * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and\n   * is not a valid boolean.\n   * @throws IllegalStateException if the array has more than one element.\n   */\n  @Override\n  public boolean getAsBoolean() {\n    if (elements.size() == 1) {\n      return elements.get(0).getAsBoolean();\n    }\n    throw new IllegalStateException();\n  }\n\n  @Override\n  public boolean equals(Object o) {\n    return (o == this) || (o instanceof JsonArray && ((JsonArray) o).elements.equals(elements));\n  }\n\n  @Override\n  public int hashCode() {\n    return elements.hashCode();\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonDeserializationContext.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport java.lang.reflect.Type;\n\n/**\n * Context for deserialization that is passed to a custom deserializer during invocation of its\n * {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)}\n * method.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic interface JsonDeserializationContext {\n\n  /**\n   * Invokes default deserialization on the specified object. It should never be invoked on\n   * the element received as a parameter of the\n   * {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)} method. Doing\n   * so will result in an infinite loop since Gson will in-turn call the custom deserializer again.\n   *\n   * @param json the parse tree.\n   * @param typeOfT type of the expected return value.\n   * @param <T> The type of the deserialized object.\n   * @return An object of type typeOfT.\n   * @throws JsonParseException if the parse tree does not contain expected data.\n   */\n  public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException;\n}"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonDeserializer.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport java.lang.reflect.Type;\n\n/**\n * <p>Interface representing a custom deserializer for Json. You should write a custom\n * deserializer, if you are not happy with the default deserialization done by Gson. You will\n * also need to register this deserializer through\n * {@link GsonBuilder#registerTypeAdapter(Type, Object)}.</p>\n *\n * <p>Let us look at example where defining a deserializer will be useful. The {@code Id} class\n * defined below has two fields: {@code clazz} and {@code value}.</p>\n *\n * <pre>\n * public class Id&lt;T&gt; {\n *   private final Class&lt;T&gt; clazz;\n *   private final long value;\n *   public Id(Class&lt;T&gt; clazz, long value) {\n *     this.clazz = clazz;\n *     this.value = value;\n *   }\n *   public long getValue() {\n *     return value;\n *   }\n * }\n * </pre>\n *\n * <p>The default deserialization of {@code Id(com.foo.MyObject.class, 20L)} will require the\n * Json string to be <code>{\"clazz\":com.foo.MyObject,\"value\":20}</code>. Suppose, you already know\n * the type of the field that the {@code Id} will be deserialized into, and hence just want to\n * deserialize it from a Json string {@code 20}. You can achieve that by writing a custom\n * deserializer:</p>\n *\n * <pre>\n * class IdDeserializer implements JsonDeserializer&lt;Id&gt;() {\n *   public Id deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)\n *       throws JsonParseException {\n *     return new Id((Class)typeOfT, id.getValue());\n *   }\n * </pre>\n *\n * <p>You will also need to register {@code IdDeserializer} with Gson as follows:</p>\n *\n * <pre>\n * Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdDeserializer()).create();\n * </pre>\n *\n * <p>New applications should prefer {@link TypeAdapter}, whose streaming API\n * is more efficient than this interface's tree API.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n *\n * @param <T> type for which the deserializer is being registered. It is possible that a\n * deserializer may be asked to deserialize a specific generic type of the T.\n */\npublic interface JsonDeserializer<T> {\n\n  /**\n   * Gson invokes this call-back method during deserialization when it encounters a field of the\n   * specified type.\n   * <p>In the implementation of this call-back method, you should consider invoking\n   * {@link JsonDeserializationContext#deserialize(JsonElement, Type)} method to create objects\n   * for any non-trivial field of the returned object. However, you should never invoke it on the\n   * the same type passing {@code json} since that will cause an infinite loop (Gson will call your\n   * call-back method again).\n   *\n   * @param json The Json data being deserialized\n   * @param typeOfT The type of the Object to deserialize to\n   * @return a deserialized object of the specified type typeOfT which is a subclass of {@code T}\n   * @throws JsonParseException if json is not in the expected format of {@code typeofT}\n   */\n  public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)\n      throws JsonParseException;\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonElement.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.Streams;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\n\n/**\n * A class representing an element of Json. It could either be a {@link JsonObject}, a\n * {@link JsonArray}, a {@link JsonPrimitive} or a {@link JsonNull}.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic abstract class JsonElement {\n  /**\n   * provides check for verifying if this element is an array or not.\n   *\n   * @return true if this element is of type {@link JsonArray}, false otherwise.\n   */\n  public boolean isJsonArray() {\n    return this instanceof JsonArray;\n  }\n\n  /**\n   * provides check for verifying if this element is a Json object or not.\n   *\n   * @return true if this element is of type {@link JsonObject}, false otherwise.\n   */\n  public boolean isJsonObject() {\n    return this instanceof JsonObject;\n  }\n\n  /**\n   * provides check for verifying if this element is a primitive or not.\n   *\n   * @return true if this element is of type {@link JsonPrimitive}, false otherwise.\n   */\n  public boolean isJsonPrimitive() {\n    return this instanceof JsonPrimitive;\n  }\n\n  /**\n   * provides check for verifying if this element represents a null value or not.\n   *\n   * @return true if this element is of type {@link JsonNull}, false otherwise.\n   * @since 1.2\n   */\n  public boolean isJsonNull() {\n    return this instanceof JsonNull;\n  }\n\n  /**\n   * convenience method to get this element as a {@link JsonObject}. If the element is of some\n   * other type, a {@link ClassCastException} will result. Hence it is best to use this method\n   * after ensuring that this element is of the desired type by calling {@link #isJsonObject()}\n   * first.\n   *\n   * @return get this element as a {@link JsonObject}.\n   * @throws IllegalStateException if the element is of another type.\n   */\n  public JsonObject getAsJsonObject() {\n    if (isJsonObject()) {\n      return (JsonObject) this;\n    }\n    throw new IllegalStateException(\"Not a JSON Object: \" + this);\n  }\n\n  /**\n   * convenience method to get this element as a {@link JsonArray}. If the element is of some\n   * other type, a {@link ClassCastException} will result. Hence it is best to use this method\n   * after ensuring that this element is of the desired type by calling {@link #isJsonArray()}\n   * first.\n   *\n   * @return get this element as a {@link JsonArray}.\n   * @throws IllegalStateException if the element is of another type.\n   */\n  public JsonArray getAsJsonArray() {\n    if (isJsonArray()) {\n      return (JsonArray) this;\n    }\n    throw new IllegalStateException(\"This is not a JSON Array.\");\n  }\n\n  /**\n   * convenience method to get this element as a {@link JsonPrimitive}. If the element is of some\n   * other type, a {@link ClassCastException} will result. Hence it is best to use this method\n   * after ensuring that this element is of the desired type by calling {@link #isJsonPrimitive()}\n   * first.\n   *\n   * @return get this element as a {@link JsonPrimitive}.\n   * @throws IllegalStateException if the element is of another type.\n   */\n  public JsonPrimitive getAsJsonPrimitive() {\n    if (isJsonPrimitive()) {\n      return (JsonPrimitive) this;\n    }\n    throw new IllegalStateException(\"This is not a JSON Primitive.\");\n  }\n\n  /**\n   * convenience method to get this element as a {@link JsonNull}. If the element is of some\n   * other type, a {@link ClassCastException} will result. Hence it is best to use this method\n   * after ensuring that this element is of the desired type by calling {@link #isJsonNull()}\n   * first.\n   *\n   * @return get this element as a {@link JsonNull}.\n   * @throws IllegalStateException if the element is of another type.\n   * @since 1.2\n   */\n  public JsonNull getAsJsonNull() {\n    if (isJsonNull()) {\n      return (JsonNull) this;\n    }\n    throw new IllegalStateException(\"This is not a JSON Null.\");\n  }\n\n  /**\n   * convenience method to get this element as a boolean value.\n   *\n   * @return get this element as a primitive boolean value.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid\n   * boolean value.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   */\n  public boolean getAsBoolean() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * convenience method to get this element as a {@link Boolean} value.\n   *\n   * @return get this element as a {@link Boolean} value.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid\n   * boolean value.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   */\n  Boolean getAsBooleanWrapper() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * convenience method to get this element as a {@link Number}.\n   *\n   * @return get this element as a {@link Number}.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid\n   * number.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   */\n  public Number getAsNumber() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * convenience method to get this element as a string value.\n   *\n   * @return get this element as a string value.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid\n   * string value.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   */\n  public String getAsString() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * convenience method to get this element as a primitive double value.\n   *\n   * @return get this element as a primitive double value.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid\n   * double value.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   */\n  public double getAsDouble() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * convenience method to get this element as a primitive float value.\n   *\n   * @return get this element as a primitive float value.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid\n   * float value.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   */\n  public float getAsFloat() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * convenience method to get this element as a primitive long value.\n   *\n   * @return get this element as a primitive long value.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid\n   * long value.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   */\n  public long getAsLong() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * convenience method to get this element as a primitive integer value.\n   *\n   * @return get this element as a primitive integer value.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid\n   * integer value.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   */\n  public int getAsInt() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * convenience method to get this element as a primitive byte value.\n   *\n   * @return get this element as a primitive byte value.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid\n   * byte value.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   * @since 1.3\n   */\n  public byte getAsByte() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * convenience method to get this element as a primitive character value.\n   *\n   * @return get this element as a primitive char value.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid\n   * char value.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   * @since 1.3\n   */\n  public char getAsCharacter() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * convenience method to get this element as a {@link BigDecimal}.\n   *\n   * @return get this element as a {@link BigDecimal}.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive}.\n   * * @throws NumberFormatException if the element is not a valid {@link BigDecimal}.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   * @since 1.2\n   */\n  public BigDecimal getAsBigDecimal() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * convenience method to get this element as a {@link BigInteger}.\n   *\n   * @return get this element as a {@link BigInteger}.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive}.\n   * @throws NumberFormatException if the element is not a valid {@link BigInteger}.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   * @since 1.2\n   */\n  public BigInteger getAsBigInteger() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * convenience method to get this element as a primitive short value.\n   *\n   * @return get this element as a primitive short value.\n   * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid\n   * short value.\n   * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains\n   * more than a single element.\n   */\n  public short getAsShort() {\n    throw new UnsupportedOperationException(getClass().getSimpleName());\n  }\n\n  /**\n   * Returns a String representation of this element.\n   */\n  @Override\n  public String toString() {\n    try {\n      StringWriter stringWriter = new StringWriter();\n      JsonWriter jsonWriter = new JsonWriter(stringWriter);\n      jsonWriter.setLenient(true);\n      Streams.write(this, jsonWriter);\n      return stringWriter.toString();\n    } catch (IOException e) {\n      throw new AssertionError(e);\n    }\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonIOException.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\n/**\n * This exception is raised when Gson was unable to read an input stream\n * or write to one.\n * \n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic final class JsonIOException extends JsonParseException {\n  private static final long serialVersionUID = 1L;\n\n  public JsonIOException(String msg) {\n    super(msg);\n  }\n\n  public JsonIOException(String msg, Throwable cause) {\n    super(msg, cause);\n  }\n\n  /**\n   * Creates exception with the specified cause. Consider using\n   * {@link #JsonIOException(String, Throwable)} instead if you can describe what happened.\n   *\n   * @param cause root exception that caused this exception to be thrown.\n   */\n  public JsonIOException(Throwable cause) {\n    super(cause);\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonNull.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\n/**\n * A class representing a Json {@code null} value.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n * @since 1.2\n */\npublic final class JsonNull extends JsonElement {\n  /**\n   * singleton for JsonNull\n   *\n   * @since 1.8\n   */\n  public static final JsonNull INSTANCE = new JsonNull();\n\n  /**\n   * Creates a new JsonNull object.\n   * Deprecated since Gson version 1.8. Use {@link #INSTANCE} instead\n   */\n  @Deprecated\n  public JsonNull() {\n    // Do nothing\n  }\n\n  /**\n   * All instances of JsonNull have the same hash code since they are indistinguishable\n   */\n  @Override\n  public int hashCode() {\n    return JsonNull.class.hashCode();\n  }\n\n  /**\n   * All instances of JsonNull are the same\n   */\n  @Override\n  public boolean equals(Object other) {\n    return this == other || other instanceof JsonNull;\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonObject.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.$Gson$Preconditions;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.StringMap;\n\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * A class representing an object type in Json. An object consists of name-value pairs where names\n * are strings, and values are any other type of {@link JsonElement}. This allows for a creating a\n * tree of JsonElements. The member elements of this object are maintained in order they were added.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic final class JsonObject extends JsonElement {\n  // We are using a linked hash map because it is important to preserve\n  // the order in which elements are inserted. This is needed to ensure\n  // that the fields of an object are inserted in the order they were\n  // defined in the class.\n  private final StringMap<JsonElement> members = new StringMap<JsonElement>();\n\n  /**\n   * Creates an empty JsonObject.\n   */\n  public JsonObject() {\n  }\n\n  /**\n   * Adds a member, which is a name-value pair, to self. The name must be a String, but the value\n   * can be an arbitrary JsonElement, thereby allowing you to build a full tree of JsonElements\n   * rooted at this node.\n   *\n   * @param property name of the member.\n   * @param value the member object.\n   */\n  public void add(String property, JsonElement value) {\n    if (value == null) {\n      value = JsonNull.INSTANCE;\n    }\n    members.put($Gson$Preconditions.checkNotNull(property), value);\n  }\n\n  /**\n   * Removes the {@code property} from this {@link JsonObject}.\n   *\n   * @param property name of the member that should be removed.\n   * @return the {@link JsonElement} object that is being removed.\n   * @since 1.3\n   */\n  public JsonElement remove(String property) {\n    return members.remove(property);\n  }\n\n  /**\n   * Convenience method to add a primitive member. The specified value is converted to a\n   * JsonPrimitive of String.\n   *\n   * @param property name of the member.\n   * @param value the string value associated with the member.\n   */\n  public void addProperty(String property, String value) {\n    add(property, createJsonElement(value));\n  }\n\n  /**\n   * Convenience method to add a primitive member. The specified value is converted to a\n   * JsonPrimitive of Number.\n   *\n   * @param property name of the member.\n   * @param value the number value associated with the member.\n   */\n  public void addProperty(String property, Number value) {\n    add(property, createJsonElement(value));\n  }\n\n  /**\n   * Convenience method to add a boolean member. The specified value is converted to a\n   * JsonPrimitive of Boolean.\n   *\n   * @param property name of the member.\n   * @param value the number value associated with the member.\n   */\n  public void addProperty(String property, Boolean value) {\n    add(property, createJsonElement(value));\n  }\n\n  /**\n   * Convenience method to add a char member. The specified value is converted to a\n   * JsonPrimitive of Character.\n   *\n   * @param property name of the member.\n   * @param value the number value associated with the member.\n   */\n  public void addProperty(String property, Character value) {\n    add(property, createJsonElement(value));\n  }\n\n  /**\n   * Creates the proper {@link JsonElement} object from the given {@code value} object.\n   *\n   * @param value the object to generate the {@link JsonElement} for\n   * @return a {@link JsonPrimitive} if the {@code value} is not null, otherwise a {@link JsonNull}\n   */\n  private JsonElement createJsonElement(Object value) {\n    return value == null ? JsonNull.INSTANCE : new JsonPrimitive(value);\n  }\n\n  /**\n   * Returns a set of members of this object. The set is ordered, and the order is in which the\n   * elements were added.\n   *\n   * @return a set of members of this object.\n   */\n  public Set<Map.Entry<String, JsonElement>> entrySet() {\n    return members.entrySet();\n  }\n\n  /**\n   * Convenience method to check if a member with the specified name is present in this object.\n   *\n   * @param memberName name of the member that is being checked for presence.\n   * @return true if there is a member with the specified name, false otherwise.\n   */\n  public boolean has(String memberName) {\n    return members.containsKey(memberName);\n  }\n\n  /**\n   * Returns the member with the specified name.\n   *\n   * @param memberName name of the member that is being requested.\n   * @return the member matching the name. Null if no such member exists.\n   */\n  public JsonElement get(String memberName) {\n    if (members.containsKey(memberName)) {\n      JsonElement member = members.get(memberName);\n      return member == null ? JsonNull.INSTANCE : member;\n    }\n    return null;\n  }\n\n  /**\n   * Convenience method to get the specified member as a JsonPrimitive element.\n   *\n   * @param memberName name of the member being requested.\n   * @return the JsonPrimitive corresponding to the specified member.\n   */\n  public JsonPrimitive getAsJsonPrimitive(String memberName) {\n    return (JsonPrimitive) members.get(memberName);\n  }\n\n  /**\n   * Convenience method to get the specified member as a JsonArray.\n   *\n   * @param memberName name of the member being requested.\n   * @return the JsonArray corresponding to the specified member.\n   */\n  public JsonArray getAsJsonArray(String memberName) {\n    return (JsonArray) members.get(memberName);\n  }\n\n  /**\n   * Convenience method to get the specified member as a JsonObject.\n   *\n   * @param memberName name of the member being requested.\n   * @return the JsonObject corresponding to the specified member.\n   */\n  public JsonObject getAsJsonObject(String memberName) {\n    return (JsonObject) members.get(memberName);\n  }\n\n  @Override\n  public boolean equals(Object o) {\n    return (o == this) || (o instanceof JsonObject\n        && ((JsonObject) o).members.equals(members));\n  }\n\n  @Override\n  public int hashCode() {\n    return members.hashCode();\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonParseException.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\n/**\n * This exception is raised if there is a serious issue that occurs during parsing of a Json\n * string.  One of the main usages for this class is for the Gson infrastructure.  If the incoming\n * Json is bad/malicious, an instance of this exception is raised.\n *\n * <p>This exception is a {@link RuntimeException} because it is exposed to the client.  Using a\n * {@link RuntimeException} avoids bad coding practices on the client side where they catch the\n * exception and do nothing.  It is often the case that you want to blow up if there is a parsing\n * error (i.e. often clients do not know how to recover from a {@link JsonParseException}.</p>\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic class JsonParseException extends RuntimeException {\n  static final long serialVersionUID = -4086729973971783390L;\n\n  /**\n   * Creates exception with the specified message. If you are wrapping another exception, consider\n   * using {@link #JsonParseException(String, Throwable)} instead.\n   *\n   * @param msg error message describing a possible cause of this exception.\n   */\n  public JsonParseException(String msg) {\n    super(msg);\n  }\n\n  /**\n   * Creates exception with the specified message and cause.\n   *\n   * @param msg error message describing what happened.\n   * @param cause root exception that caused this exception to be thrown.\n   */\n  public JsonParseException(String msg, Throwable cause) {\n    super(msg, cause);\n  }\n\n  /**\n   * Creates exception with the specified cause. Consider using\n   * {@link #JsonParseException(String, Throwable)} instead if you can describe what happened.\n   *\n   * @param cause root exception that caused this exception to be thrown.\n   */\n  public JsonParseException(Throwable cause) {\n    super(cause);\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonParser.java",
    "content": "/*\n * Copyright (C) 2009 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.Streams;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.MalformedJsonException;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.StringReader;\n\n/**\n * A parser to parse Json into a parse tree of {@link JsonElement}s\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n * @since 1.3\n */\npublic final class JsonParser {\n\n  /**\n   * Parses the specified JSON string into a parse tree\n   *\n   * @param json JSON text\n   * @return a parse tree of {@link JsonElement}s corresponding to the specified JSON\n   * @throws JsonParseException if the specified text is not valid JSON\n   * @since 1.3\n   */\n  public JsonElement parse(String json) throws JsonSyntaxException {\n    return parse(new StringReader(json));\n  }\n\n  /**\n   * Parses the specified JSON string into a parse tree\n   *\n   * @param json JSON text\n   * @return a parse tree of {@link JsonElement}s corresponding to the specified JSON\n   * @throws JsonParseException if the specified text is not valid JSON\n   * @since 1.3\n   */\n  public JsonElement parse(Reader json) throws JsonIOException, JsonSyntaxException {\n    try {\n      JsonReader jsonReader = new JsonReader(json);\n      JsonElement element = parse(jsonReader);\n      if (!element.isJsonNull() && jsonReader.peek() != JsonToken.END_DOCUMENT) {\n        throw new JsonSyntaxException(\"Did not consume the entire document.\");\n      }\n      return element;\n    } catch (MalformedJsonException e) {\n      throw new JsonSyntaxException(e);\n    } catch (IOException e) {\n      throw new JsonIOException(e);\n    } catch (NumberFormatException e) {\n      throw new JsonSyntaxException(e);\n    }\n  }\n\n  /**\n   * Returns the next value from the JSON stream as a parse tree.\n   *\n   * @throws JsonParseException if there is an IOException or if the specified\n   *     text is not valid JSON\n   * @since 1.6\n   */\n  public JsonElement parse(JsonReader json) throws JsonIOException, JsonSyntaxException {\n    boolean lenient = json.isLenient();\n    json.setLenient(true);\n    try {\n      return Streams.parse(json);\n    } catch (StackOverflowError e) {\n      throw new JsonParseException(\"Failed parsing JSON source: \" + json + \" to Json\", e);\n    } catch (OutOfMemoryError e) {\n      throw new JsonParseException(\"Failed parsing JSON source: \" + json + \" to Json\", e);\n    } finally {\n      json.setLenient(lenient);\n    }\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonPrimitive.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.$Gson$Preconditions;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.LazilyParsedNumber;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\n\n/**\n * A class representing a Json primitive value. A primitive value\n * is either a String, a Java primitive, or a Java primitive\n * wrapper type.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic final class JsonPrimitive extends JsonElement {\n\n  private static final Class<?>[] PRIMITIVE_TYPES = { int.class, long.class, short.class,\n      float.class, double.class, byte.class, boolean.class, char.class, Integer.class, Long.class,\n      Short.class, Float.class, Double.class, Byte.class, Boolean.class, Character.class };\n\n  private Object value;\n\n  /**\n   * Create a primitive containing a boolean value.\n   *\n   * @param bool the value to create the primitive with.\n   */\n  public JsonPrimitive(Boolean bool) {\n    setValue(bool);\n  }\n\n  /**\n   * Create a primitive containing a {@link Number}.\n   *\n   * @param number the value to create the primitive with.\n   */\n  public JsonPrimitive(Number number) {\n    setValue(number);\n  }\n\n  /**\n   * Create a primitive containing a String value.\n   *\n   * @param string the value to create the primitive with.\n   */\n  public JsonPrimitive(String string) {\n    setValue(string);\n  }\n\n  /**\n   * Create a primitive containing a character. The character is turned into a one character String\n   * since Json only supports String.\n   *\n   * @param c the value to create the primitive with.\n   */\n  public JsonPrimitive(Character c) {\n    setValue(c);\n  }\n\n  /**\n   * Create a primitive using the specified Object. It must be an instance of {@link Number}, a\n   * Java primitive type, or a String.\n   *\n   * @param primitive the value to create the primitive with.\n   */\n  JsonPrimitive(Object primitive) {\n    setValue(primitive);\n  }\n\n  void setValue(Object primitive) {\n    if (primitive instanceof Character) {\n      // convert characters to strings since in JSON, characters are represented as a single\n      // character string\n      char c = ((Character) primitive).charValue();\n      this.value = String.valueOf(c);\n    } else {\n      $Gson$Preconditions.checkArgument(primitive instanceof Number\n              || isPrimitiveOrString(primitive));\n      this.value = primitive;\n    }\n  }\n\n  /**\n   * Check whether this primitive contains a boolean value.\n   *\n   * @return true if this primitive contains a boolean value, false otherwise.\n   */\n  public boolean isBoolean() {\n    return value instanceof Boolean;\n  }\n\n  /**\n   * convenience method to get this element as a {@link Boolean}.\n   *\n   * @return get this element as a {@link Boolean}.\n   */\n  @Override\n  Boolean getAsBooleanWrapper() {\n    return (Boolean) value;\n  }\n\n  /**\n   * convenience method to get this element as a boolean value.\n   *\n   * @return get this element as a primitive boolean value.\n   */\n  @Override\n  public boolean getAsBoolean() {\n    if (isBoolean()) {\n      return getAsBooleanWrapper().booleanValue();\n    } else {\n      // Check to see if the value as a String is \"true\" in any case.\n      return Boolean.parseBoolean(getAsString());\n    }\n  }\n\n  /**\n   * Check whether this primitive contains a Number.\n   *\n   * @return true if this primitive contains a Number, false otherwise.\n   */\n  public boolean isNumber() {\n    return value instanceof Number;\n  }\n\n  /**\n   * convenience method to get this element as a Number.\n   *\n   * @return get this element as a Number.\n   * @throws NumberFormatException if the value contained is not a valid Number.\n   */\n  @Override\n  public Number getAsNumber() {\n    return value instanceof String ? new LazilyParsedNumber((String) value) : (Number) value;\n  }\n\n  /**\n   * Check whether this primitive contains a String value.\n   *\n   * @return true if this primitive contains a String value, false otherwise.\n   */\n  public boolean isString() {\n    return value instanceof String;\n  }\n\n  /**\n   * convenience method to get this element as a String.\n   *\n   * @return get this element as a String.\n   */\n  @Override\n  public String getAsString() {\n    if (isNumber()) {\n      return getAsNumber().toString();\n    } else if (isBoolean()) {\n      return getAsBooleanWrapper().toString();\n    } else {\n      return (String) value;\n    }\n  }\n\n  /**\n   * convenience method to get this element as a primitive double.\n   *\n   * @return get this element as a primitive double.\n   * @throws NumberFormatException if the value contained is not a valid double.\n   */\n  @Override\n  public double getAsDouble() {\n    return isNumber() ? getAsNumber().doubleValue() : Double.parseDouble(getAsString());\n  }\n\n  /**\n   * convenience method to get this element as a {@link BigDecimal}.\n   *\n   * @return get this element as a {@link BigDecimal}.\n   * @throws NumberFormatException if the value contained is not a valid {@link BigDecimal}.\n   */\n  @Override\n  public BigDecimal getAsBigDecimal() {\n    return value instanceof BigDecimal ? (BigDecimal) value : new BigDecimal(value.toString());\n  }\n\n  /**\n   * convenience method to get this element as a {@link BigInteger}.\n   *\n   * @return get this element as a {@link BigInteger}.\n   * @throws NumberFormatException if the value contained is not a valid {@link BigInteger}.\n   */\n  @Override\n  public BigInteger getAsBigInteger() {\n    return value instanceof BigInteger ?\n        (BigInteger) value : new BigInteger(value.toString());\n  }\n\n  /**\n   * convenience method to get this element as a float.\n   *\n   * @return get this element as a float.\n   * @throws NumberFormatException if the value contained is not a valid float.\n   */\n  @Override\n  public float getAsFloat() {\n    return isNumber() ? getAsNumber().floatValue() : Float.parseFloat(getAsString());\n  }\n\n  /**\n   * convenience method to get this element as a primitive long.\n   *\n   * @return get this element as a primitive long.\n   * @throws NumberFormatException if the value contained is not a valid long.\n   */\n  @Override\n  public long getAsLong() {\n    return isNumber() ? getAsNumber().longValue() : Long.parseLong(getAsString());\n  }\n\n  /**\n   * convenience method to get this element as a primitive short.\n   *\n   * @return get this element as a primitive short.\n   * @throws NumberFormatException if the value contained is not a valid short value.\n   */\n  @Override\n  public short getAsShort() {\n    return isNumber() ? getAsNumber().shortValue() : Short.parseShort(getAsString());\n  }\n\n /**\n  * convenience method to get this element as a primitive integer.\n  *\n  * @return get this element as a primitive integer.\n  * @throws NumberFormatException if the value contained is not a valid integer.\n  */\n  @Override\n  public int getAsInt() {\n    return isNumber() ? getAsNumber().intValue() : Integer.parseInt(getAsString());\n  }\n\n  @Override\n  public byte getAsByte() {\n    return isNumber() ? getAsNumber().byteValue() : Byte.parseByte(getAsString());\n  }\n\n  @Override\n  public char getAsCharacter() {\n    return getAsString().charAt(0);\n  }\n\n  private static boolean isPrimitiveOrString(Object target) {\n    if (target instanceof String) {\n      return true;\n    }\n\n    Class<?> classOfPrimitive = target.getClass();\n    for (Class<?> standardPrimitive : PRIMITIVE_TYPES) {\n      if (standardPrimitive.isAssignableFrom(classOfPrimitive)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  @Override\n  public int hashCode() {\n    if (value == null) {\n      return 31;\n    }\n    // Using recommended hashing algorithm from Effective Java for longs and doubles\n    if (isIntegral(this)) {\n      long value = getAsNumber().longValue();\n      return (int) (value ^ (value >>> 32));\n    }\n    if (value instanceof Number) {\n      long value = Double.doubleToLongBits(getAsNumber().doubleValue());\n      return (int) (value ^ (value >>> 32));\n    }\n    return value.hashCode();\n  }\n\n  @Override\n  public boolean equals(Object obj) {\n    if (this == obj) {\n      return true;\n    }\n    if (obj == null || getClass() != obj.getClass()) {\n      return false;\n    }\n    JsonPrimitive other = (JsonPrimitive)obj;\n    if (value == null) {\n      return other.value == null;\n    }\n    if (isIntegral(this) && isIntegral(other)) {\n      return getAsNumber().longValue() == other.getAsNumber().longValue();\n    }\n    if (value instanceof Number && other.value instanceof Number) {\n      double a = getAsNumber().doubleValue();\n      // Java standard types other than double return true for two NaN. So, need\n      // special handling for double.\n      double b = other.getAsNumber().doubleValue();\n      return a == b || (Double.isNaN(a) && Double.isNaN(b));\n    }\n    return value.equals(other.value);\n  }\n\n  /**\n   * Returns true if the specified number is an integral type\n   * (Long, Integer, Short, Byte, BigInteger)\n   */\n  private static boolean isIntegral(JsonPrimitive primitive) {\n    if (primitive.value instanceof Number) {\n      Number number = (Number) primitive.value;\n      return number instanceof BigInteger || number instanceof Long || number instanceof Integer\n          || number instanceof Short || number instanceof Byte;\n    }\n    return false;\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonSerializationContext.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport java.lang.reflect.Type;\n\n/**\n * Context for serialization that is passed to a custom serializer during invocation of its\n * {@link JsonSerializer#serialize(Object, Type, JsonSerializationContext)} method.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic interface JsonSerializationContext {\n\n  /**\n   * Invokes default serialization on the specified object.\n   *\n   * @param src the object that needs to be serialized.\n   * @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}.\n   */\n  public JsonElement serialize(Object src);\n\n  /**\n   * Invokes default serialization on the specified object passing the specific type information.\n   * It should never be invoked on the element received as a parameter of the\n   * {@link JsonSerializer#serialize(Object, Type, JsonSerializationContext)} method. Doing\n   * so will result in an infinite loop since Gson will in-turn call the custom serializer again.\n   *\n   * @param src the object that needs to be serialized.\n   * @param typeOfSrc the actual genericized type of src object.\n   * @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}.\n   */\n  public JsonElement serialize(Object src, Type typeOfSrc);\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonSerializer.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport java.lang.reflect.Type;\n\n/**\n * Interface representing a custom serializer for Json. You should write a custom serializer, if\n * you are not happy with the default serialization done by Gson. You will also need to register\n * this serializer through {@link GsonBuilder#registerTypeAdapter(Type, Object)}.\n *\n * <p>Let us look at example where defining a serializer will be useful. The {@code Id} class\n * defined below has two fields: {@code clazz} and {@code value}.</p>\n *\n * <p><pre>\n * public class Id&lt;T&gt; {\n *   private final Class&lt;T&gt; clazz;\n *   private final long value;\n *\n *   public Id(Class&lt;T&gt; clazz, long value) {\n *     this.clazz = clazz;\n *     this.value = value;\n *   }\n *\n *   public long getValue() {\n *     return value;\n *   }\n * }\n * </pre></p>\n *\n * <p>The default serialization of {@code Id(com.foo.MyObject.class, 20L)} will be\n * <code>{\"clazz\":com.foo.MyObject,\"value\":20}</code>. Suppose, you just want the output to be\n * the value instead, which is {@code 20} in this case. You can achieve that by writing a custom\n * serializer:</p>\n *\n * <p><pre>\n * class IdSerializer implements JsonSerializer&lt;Id&gt;() {\n *   public JsonElement serialize(Id id, Type typeOfId, JsonSerializationContext context) {\n *     return new JsonPrimitive(id.getValue());\n *   }\n * }\n * </pre></p>\n *\n * <p>You will also need to register {@code IdSerializer} with Gson as follows:</p>\n * <pre>\n * Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdSerializer()).create();\n * </pre>\n *\n * <p>New applications should prefer {@link TypeAdapter}, whose streaming API\n * is more efficient than this interface's tree API.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n *\n * @param <T> type for which the serializer is being registered. It is possible that a serializer\n *        may be asked to serialize a specific generic type of the T.\n */\npublic interface JsonSerializer<T> {\n\n  /**\n   * Gson invokes this call-back method during serialization when it encounters a field of the\n   * specified type.\n   *\n   * <p>In the implementation of this call-back method, you should consider invoking\n   * {@link JsonSerializationContext#serialize(Object, Type)} method to create JsonElements for any\n   * non-trivial field of the {@code src} object. However, you should never invoke it on the\n   * {@code src} object itself since that will cause an infinite loop (Gson will call your\n   * call-back method again).</p>\n   *\n   * @param src the object that needs to be converted to Json.\n   * @param typeOfSrc the actual type (fully genericized version) of the source object.\n   * @return a JsonElement corresponding to the specified object.\n   */\n  public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context);\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonStreamParser.java",
    "content": "/*\n * Copyright (C) 2009 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.Streams;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.MalformedJsonException;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.util.Iterator;\nimport java.util.NoSuchElementException;\n\n/**\n * A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader\n * asynchronously.\n * \n * <p>This class is conditionally thread-safe (see Item 70, Effective Java second edition). To\n * properly use this class across multiple threads, you will need to add some external\n * synchronization.  For example:\n * \n * <pre>\n * JsonStreamParser parser = new JsonStreamParser(\"['first'] {'second':10} 'third'\");\n * JsonElement element;\n * synchronized (parser) {  // synchronize on an object shared by threads\n *   if (parser.hasNext()) {\n *     element = parser.next();\n *   }\n * }\n * </pre>\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n * @since 1.4\n */\npublic final class JsonStreamParser implements Iterator<JsonElement> {\n  private final JsonReader parser;\n  private final Object lock;\n\n  /**\n   * @param json The string containing JSON elements concatenated to each other.\n   * @since 1.4\n   */\n  public JsonStreamParser(String json) {\n    this(new StringReader(json));\n  }\n  \n  /**\n   * @param reader The data stream containing JSON elements concatenated to each other.\n   * @since 1.4\n   */\n  public JsonStreamParser(Reader reader) {\n    parser = new JsonReader(reader);\n    parser.setLenient(true);\n    lock = new Object();\n  }\n  \n  /**\n   * Returns the next available {@link JsonElement} on the reader. Null if none available.\n   * \n   * @return the next available {@link JsonElement} on the reader. Null if none available.\n   * @throws JsonParseException if the incoming stream is malformed JSON.\n   * @since 1.4\n   */\n  public JsonElement next() throws JsonParseException {\n    if (!hasNext()) {\n      throw new NoSuchElementException();\n    }\n    \n    try {\n      return Streams.parse(parser);\n    } catch (StackOverflowError e) {\n      throw new JsonParseException(\"Failed parsing JSON source to Json\", e);\n    } catch (OutOfMemoryError e) {\n      throw new JsonParseException(\"Failed parsing JSON source to Json\", e);\n    } catch (JsonParseException e) {\n      throw e.getCause() instanceof EOFException ? new NoSuchElementException() : e;\n    }\n  }\n\n  /**\n   * Returns true if a {@link JsonElement} is available on the input for consumption\n   * @return true if a {@link JsonElement} is available on the input, false otherwise\n   * @since 1.4\n   */\n  public boolean hasNext() {\n    synchronized (lock) {\n      try {\n        return parser.peek() != JsonToken.END_DOCUMENT;\n      } catch (MalformedJsonException e) {\n        throw new JsonSyntaxException(e);\n      } catch (IOException e) {\n        throw new JsonIOException(e);\n      }\n    }\n  }\n\n  /**\n   * This optional {@link Iterator} method is not relevant for stream parsing and hence is not\n   * implemented.\n   * @since 1.4\n   */\n  public void remove() {\n    throw new UnsupportedOperationException();\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/JsonSyntaxException.java",
    "content": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\n/**\n * This exception is raised when Gson attempts to read (or write) a malformed\n * JSON element.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic final class JsonSyntaxException extends JsonParseException {\n\n  private static final long serialVersionUID = 1L;\n\n  public JsonSyntaxException(String msg) {\n    super(msg);\n  }\n\n  public JsonSyntaxException(String msg, Throwable cause) {\n    super(msg, cause);\n  }\n\n  /**\n   * Creates exception with the specified cause. Consider using\n   * {@link #JsonSyntaxException(String, Throwable)} instead if you can\n   * describe what actually happened.\n   *\n   * @param cause root exception that caused this exception to be thrown.\n   */\n  public JsonSyntaxException(Throwable cause) {\n    super(cause);\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/LongSerializationPolicy.java",
    "content": "/*\n * Copyright (C) 2009 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\n/**\n * Defines the expected format for a {@code long} or {@code Long} type when its serialized.\n *\n * @since 1.3\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic enum LongSerializationPolicy {\n  /**\n   * This is the \"default\" serialization policy that will output a {@code long} object as a JSON\n   * number.  For example, assume an object has a long field named \"f\" then the serialized output\n   * would be:\n   * {@code {\"f\":123}}.\n   */\n  DEFAULT() {\n    public JsonElement serialize(Long value) {\n      return new JsonPrimitive(value);\n    }\n  },\n  \n  /**\n   * Serializes a long value as a quoted string.  For example, assume an object has a long field \n   * named \"f\" then the serialized output would be:\n   * {@code {\"f\":\"123\"}}.\n   */\n  STRING() {\n    public JsonElement serialize(Long value) {\n      return new JsonPrimitive(String.valueOf(value));\n    }\n  };\n  \n  /**\n   * Serialize this {@code value} using this serialization policy.\n   *\n   * @param value the long value to be serialized into a {@link JsonElement}\n   * @return the serialized version of {@code value}\n   */\n  public abstract JsonElement serialize(Long value);\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/TreeTypeAdapter.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.$Gson$Preconditions;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.Streams;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\n\n/**\n * Adapts a Gson 1.x tree-style adapter as a streaming TypeAdapter. Since the\n * tree adapter may be serialization-only or deserialization-only, this class\n * has a facility to lookup a delegate type adapter on demand.\n */\nfinal class TreeTypeAdapter<T> extends TypeAdapter<T> {\n  private final JsonSerializer<T> serializer;\n  private final JsonDeserializer<T> deserializer;\n  private final Gson gson;\n  private final TypeToken<T> typeToken;\n  private final TypeAdapterFactory skipPast;\n\n  /** The delegate is lazily created because it may not be needed, and creating it may fail. */\n  private TypeAdapter<T> delegate;\n\n  private TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer,\n      Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) {\n    this.serializer = serializer;\n    this.deserializer = deserializer;\n    this.gson = gson;\n    this.typeToken = typeToken;\n    this.skipPast = skipPast;\n  }\n\n  @Override\n  public T read(JsonReader in) throws IOException {\n    if (deserializer == null) {\n      return delegate().read(in);\n    }\n    JsonElement value = Streams.parse(in);\n    if (value.isJsonNull()) {\n      return null;\n    }\n    return deserializer.deserialize(value, typeToken.getType(), gson.deserializationContext);\n  }\n\n  @Override\n  public void write(JsonWriter out, T value) throws IOException {\n    if (serializer == null) {\n      delegate().write(out, value);\n      return;\n    }\n    if (value == null) {\n      out.nullValue();\n      return;\n    }\n    JsonElement tree = serializer.serialize(value, typeToken.getType(), gson.serializationContext);\n    Streams.write(tree, out);\n  }\n\n  private TypeAdapter<T> delegate() {\n    TypeAdapter<T> d = delegate;\n    return d != null\n        ? d\n        : (delegate = gson.getDelegateAdapter(skipPast, typeToken));\n  }\n\n  /**\n   * Returns a new factory that will match each type against {@code exactType}.\n   */\n  public static TypeAdapterFactory newFactory(TypeToken<?> exactType, Object typeAdapter) {\n    return new SingleTypeFactory(typeAdapter, exactType, false, null);\n  }\n\n  /**\n   * Returns a new factory that will match each type and its raw type against\n   * {@code exactType}.\n   */\n  public static TypeAdapterFactory newFactoryWithMatchRawType(\n      TypeToken<?> exactType, Object typeAdapter) {\n    // only bother matching raw types if exact type is a raw type\n    boolean matchRawType = exactType.getType() == exactType.getRawType();\n    return new SingleTypeFactory(typeAdapter, exactType, matchRawType, null);\n  }\n\n  /**\n   * Returns a new factory that will match each type's raw type for assignability\n   * to {@code hierarchyType}.\n   */\n  public static TypeAdapterFactory newTypeHierarchyFactory(\n          Class<?> hierarchyType, Object typeAdapter) {\n    return new SingleTypeFactory(typeAdapter, null, false, hierarchyType);\n  }\n\n  private static class SingleTypeFactory implements TypeAdapterFactory {\n    private final TypeToken<?> exactType;\n    private final boolean matchRawType;\n    private final Class<?> hierarchyType;\n    private final JsonSerializer<?> serializer;\n    private final JsonDeserializer<?> deserializer;\n\n    private SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, boolean matchRawType,\n                              Class<?> hierarchyType) {\n      serializer = typeAdapter instanceof JsonSerializer\n          ? (JsonSerializer<?>) typeAdapter\n          : null;\n      deserializer = typeAdapter instanceof JsonDeserializer\n          ? (JsonDeserializer<?>) typeAdapter\n          : null;\n      $Gson$Preconditions.checkArgument(serializer != null || deserializer != null);\n      this.exactType = exactType;\n      this.matchRawType = matchRawType;\n      this.hierarchyType = hierarchyType;\n    }\n\n    @SuppressWarnings(\"unchecked\") // guarded by typeToken.equals() call\n    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {\n      boolean matches = exactType != null\n          ? exactType.equals(type) || matchRawType && exactType.getType() == type.getRawType()\n          : hierarchyType.isAssignableFrom(type.getRawType());\n      return matches\n          ? new TreeTypeAdapter<T>((JsonSerializer<T>) serializer,\n              (JsonDeserializer<T>) deserializer, gson, type, this)\n          : null;\n    }\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/TypeAdapter.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.JsonTreeReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.JsonTreeWriter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.io.Writer;\n\n/**\n * Converts Java objects to and from JSON.\n *\n * <h3>Defining a type's JSON form</h3>\n * By default Gson converts application classes to JSON using its built-in type\n * adapters. If Gson's default JSON conversion isn't appropriate for a type,\n * extend this class to customize the conversion. Here's an example of a type\n * adapter for an (X,Y) coordinate point: <pre>   {@code\n *\n *   public class PointAdapter extends TypeAdapter<Point> {\n *     public Point read(JsonReader reader) throws IOException {\n *       if (reader.peek() == JsonToken.NULL) {\n *         reader.nextNull();\n *         return null;\n *       }\n *       String xy = reader.nextString();\n *       String[] parts = xy.split(\",\");\n *       int x = Integer.parseInt(parts[0]);\n *       int y = Integer.parseInt(parts[1]);\n *       return new Point(x, y);\n *     }\n *     public void write(JsonWriter writer, Point value) throws IOException {\n *       if (value == null) {\n *         writer.nullValue();\n *         return;\n *       }\n *       String xy = value.getX() + \",\" + value.getY();\n *       writer.value(xy);\n *     }\n *   }}</pre>\n * With this type adapter installed, Gson will convert {@code Points} to JSON as\n * strings like {@code \"5,8\"} rather than objects like {@code {\"x\":5,\"y\":8}}. In\n * this case the type adapter binds a rich Java class to a compact JSON value.\n *\n * <p>The {@link #read(JsonReader) read()} method must read exactly one value\n * and {@link #write(JsonWriter, Object) write()} must write exactly one value.\n * For primitive types this is means readers should make exactly one call to\n * {@code nextBoolean()}, {@code nextDouble()}, {@code nextInt()}, {@code\n * nextLong()}, {@code nextString()} or {@code nextNull()}. Writers should make\n * exactly one call to one of <code>value()</code> or <code>nullValue()</code>.\n * For arrays, type adapters should start with a call to {@code beginArray()},\n * convert all elements, and finish with a call to {@code endArray()}. For\n * objects, they should start with {@code beginObject()}, convert the object,\n * and finish with {@code endObject()}. Failing to convert a value or converting\n * too many values may cause the application to crash.\n *\n * <p>Type adapters should be prepared to read null from the stream and write it\n * to the stream. Alternatively, they should use {@link #nullSafe()} method while\n * registering the type adapter with Gson. If your {@code Gson} instance\n * has been configured to {@link GsonBuilder#serializeNulls()}, these nulls will be\n * written to the final document. Otherwise the value (and the corresponding name\n * when writing to a JSON object) will be omitted automatically. In either case\n * your type adapter must handle null.\n *\n * <p>To use a custom type adapter with Gson, you must <i>register</i> it with a\n * {@link GsonBuilder}: <pre>   {@code\n *\n *   GsonBuilder builder = new GsonBuilder();\n *   builder.registerTypeAdapter(Point.class, new PointAdapter());\n *   // if PointAdapter didn't check for nulls in its read/write methods, you should instead use\n *   // builder.registerTypeAdapter(Point.class, new PointAdapter().nullSafe());\n *   ...\n *   Gson gson = builder.create();\n * }</pre>\n *\n * @since 2.1\n */\n// non-Javadoc:\n//\n// <h3>JSON Conversion</h3>\n// <p>A type adapter registered with Gson is automatically invoked while serializing\n// or deserializing JSON. However, you can also use type adapters directly to serialize\n// and deserialize JSON. Here is an example for deserialization: <pre>   {@code\n//\n//   String json = \"{'origin':'0,0','points':['1,2','3,4']}\";\n//   TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class);\n//   Graph graph = graphAdapter.fromJson(json);\n// }</pre>\n// And an example for serialization: <pre>   {@code\n//\n//   Graph graph = new Graph(...);\n//   TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class);\n//   String json = graphAdapter.toJson(graph);\n// }</pre>\n//\n// <p>Type adapters are <strong>type-specific</strong>. For example, a {@code\n// TypeAdapter<Date>} can convert {@code Date} instances to JSON and JSON to\n// instances of {@code Date}, but cannot convert any other types.\n//\npublic abstract class TypeAdapter<T> {\n\n  /**\n   * Writes one JSON value (an array, object, string, number, boolean or null)\n   * for {@code value}.\n   *\n   * @param value the Java object to write. May be null.\n   */\n  public abstract void write(JsonWriter out, T value) throws IOException;\n\n  /**\n   * Converts {@code value} to a JSON document and writes it to {@code out}.\n   * Unlike Gson's similar {@link Gson#toJson(JsonElement, Appendable) toJson}\n   * method, this write is strict. Create a {@link\n   * JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call\n   * {@link #write(JsonWriter, Object)} for lenient\n   * writing.\n   *\n   * @param value the Java object to convert. May be null.\n   * @since 2.2\n   */\n  public final void toJson(Writer out, T value) throws IOException {\n    JsonWriter writer = new JsonWriter(out);\n    write(writer, value);\n  }\n\n  /**\n   * This wrapper method is used to make a type adapter null tolerant. In general, a\n   * type adapter is required to handle nulls in write and read methods. Here is how this\n   * is typically done:<br>\n   * <pre>   {@code\n   *\n   * Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,\n   *   new TypeAdapter<Foo>() {\n   *     public Foo read(JsonReader in) throws IOException {\n   *       if (in.peek() == JsonToken.NULL) {\n   *         in.nextNull();\n   *         return null;\n   *       }\n   *       // read a Foo from in and return it\n   *     }\n   *     public void write(JsonWriter out, Foo src) throws IOException {\n   *       if (src == null) {\n   *         out.nullValue();\n   *         return;\n   *       }\n   *       // write src as JSON to out\n   *     }\n   *   }).create();\n   * }</pre>\n   * You can avoid this boilerplate handling of nulls by wrapping your type adapter with\n   * this method. Here is how we will rewrite the above example:\n   * <pre>   {@code\n   *\n   * Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,\n   *   new TypeAdapter<Foo>() {\n   *     public Foo read(JsonReader in) throws IOException {\n   *       // read a Foo from in and return it\n   *     }\n   *     public void write(JsonWriter out, Foo src) throws IOException {\n   *       // write src as JSON to out\n   *     }\n   *   }.nullSafe()).create();\n   * }</pre>\n   * Note that we didn't need to check for nulls in our type adapter after we used nullSafe.\n   */\n  public final TypeAdapter<T> nullSafe() {\n    return new TypeAdapter<T>() {\n      @Override\n      public void write(JsonWriter out, T value) throws IOException {\n        if (value == null) {\n          out.nullValue();\n        } else {\n          TypeAdapter.this.write(out, value);\n        }\n      }\n      @Override\n      public T read(JsonReader reader) throws IOException {\n        if (reader.peek() == JsonToken.NULL) {\n          reader.nextNull();\n          return null;\n        }\n        return TypeAdapter.this.read(reader);\n      }\n    };\n  }\n\n  /**\n   * Converts {@code value} to a JSON document. Unlike Gson's similar {@link\n   * Gson#toJson(Object) toJson} method, this write is strict. Create a {@link\n   * JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call\n   * {@link #write(JsonWriter, Object)} for lenient\n   * writing.\n   *\n   * @param value the Java object to convert. May be null.\n   * @since 2.2\n   */\n  public final String toJson(T value) throws IOException {\n    StringWriter stringWriter = new StringWriter();\n    toJson(stringWriter, value);\n    return stringWriter.toString();\n  }\n\n  /**\n   * Converts {@code value} to a JSON tree.\n   *\n   * @param value the Java object to convert. May be null.\n   * @return the converted JSON tree. May be {@link JsonNull}.\n   * @since 2.2\n   */\n  public final JsonElement toJsonTree(T value) {\n    try {\n      JsonTreeWriter jsonWriter = new JsonTreeWriter();\n      write(jsonWriter, value);\n      return jsonWriter.get();\n    } catch (IOException e) {\n      throw new JsonIOException(e);\n    }\n  }\n\n  /**\n   * Reads one JSON value (an array, object, string, number, boolean or null)\n   * and converts it to a Java object. Returns the converted object.\n   *\n   * @return the converted Java object. May be null.\n   */\n  public abstract T read(JsonReader in) throws IOException;\n\n  /**\n   * Converts the JSON document in {@code in} to a Java object. Unlike Gson's\n   * similar {@link Gson#fromJson(Reader, Class) fromJson} method, this\n   * read is strict. Create a {@link JsonReader#setLenient(boolean) lenient}\n   * {@code JsonReader} and call {@link #read(JsonReader)} for lenient reading.\n   *\n   * @return the converted Java object. May be null.\n   * @since 2.2\n   */\n  public final T fromJson(Reader in) throws IOException {\n    JsonReader reader = new JsonReader(in);\n    return read(reader);\n  }\n\n  /**\n   * Converts the JSON document in {@code json} to a Java object. Unlike Gson's\n   * similar {@link Gson#fromJson(String, Class) fromJson} method, this read is\n   * strict. Create a {@link JsonReader#setLenient(boolean) lenient} {@code\n   * JsonReader} and call {@link #read(JsonReader)} for lenient reading.\n   *\n   * @return the converted Java object. May be null.\n   * @since 2.2\n   */\n  public final T fromJson(String json) throws IOException {\n    return fromJson(new StringReader(json));\n  }\n\n  /**\n   * Converts {@code jsonTree} to a Java object.\n   *\n   * @param jsonTree the Java object to convert. May be {@link JsonNull}.\n   * @since 2.2\n   */\n  public final T fromJsonTree(JsonElement jsonTree) {\n    try {\n      JsonReader jsonReader = new JsonTreeReader(jsonTree);\n      return read(jsonReader);\n    } catch (IOException e) {\n      throw new JsonIOException(e);\n    }\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/TypeAdapterFactory.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;\n\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\n\n/**\n * Creates type adapters for set of related types. Type adapter factories are\n * most useful when several types share similar structure in their JSON form.\n *\n * <h3>Example: Converting enums to lowercase</h3>\n * In this example, we implement a factory that creates type adapters for all\n * enums. The type adapters will write enums in lowercase, despite the fact\n * that they're defined in {@code CONSTANT_CASE} in the corresponding Java\n * model: <pre>   {@code\n *\n *   public class LowercaseEnumTypeAdapterFactory implements TypeAdapter.Factory {\n *     public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {\n *       Class<T> rawType = (Class<T>) type.getRawType();\n *       if (!rawType.isEnum()) {\n *         return null;\n *       }\n *\n *       final Map<String, T> lowercaseToConstant = new HashMap<String, T>();\n *       for (T constant : rawType.getEnumConstants()) {\n *         lowercaseToConstant.put(toLowercase(constant), constant);\n *       }\n *\n *       return new TypeAdapter<T>() {\n *         public void write(JsonWriter out, T value) throws IOException {\n *           if (value == null) {\n *             out.nullValue();\n *           } else {\n *             out.value(toLowercase(value));\n *           }\n *         }\n *\n *         public T read(JsonReader reader) throws IOException {\n *           if (reader.peek() == JsonToken.NULL) {\n *             reader.nextNull();\n *             return null;\n *           } else {\n *             return lowercaseToConstant.get(reader.nextString());\n *           }\n *         }\n *       };\n *     }\n *\n *     private String toLowercase(Object o) {\n *       return o.toString().toLowerCase(Locale.US);\n *     }\n *   }\n * }</pre>\n *\n * <p>Type adapter factories select which types they provide type adapters\n * for. If a factory cannot support a given type, it must return null when\n * that type is passed to {@link #create}. Factories should expect {@code\n * create()} to be called on them for many types and should return null for\n * most of those types. In the above example the factory returns null for\n * calls to {@code create()} where {@code type} is not an enum.\n *\n * <p>A factory is typically called once per type, but the returned type\n * adapter may be used many times. It is most efficient to do expensive work\n * like reflection in {@code create()} so that the type adapter's {@code\n * read()} and {@code write()} methods can be very fast. In this example the\n * mapping from lowercase name to enum value is computed eagerly.\n *\n * <p>As with type adapters, factories must be <i>registered</i> with a {@link\n * GsonBuilder} for them to take effect: <pre>   {@code\n *\n *  GsonBuilder builder = new GsonBuilder();\n *  builder.registerTypeAdapterFactory(new LowercaseEnumTypeAdapterFactory());\n *  ...\n *  Gson gson = builder.create();\n * }</pre>\n * If multiple factories support the same type, the factory registered earlier\n * takes precedence.\n *\n * <h3>Example: composing other type adapters</h3>\n * In this example we implement a factory for Guava's {@code Multiset}\n * collection type. The factory can be used to create type adapters for\n * multisets of any element type: the type adapter for {@code\n * Multiset<String>} is different from the type adapter for {@code\n * Multiset<URL>}.\n *\n * <p>The type adapter <i>delegates</i> to another type adapter for the\n * multiset elements. It figures out the element type by reflecting on the\n * multiset's type token. A {@code Gson} is passed in to {@code create} for\n * just this purpose: <pre>   {@code\n *\n *   public class MultisetTypeAdapterFactory implements TypeAdapter.Factory {\n *     public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n *       Type type = typeToken.getType();\n *       if (typeToken.getRawType() != Multiset.class\n *           || !(type instanceof ParameterizedType)) {\n *         return null;\n *       }\n *\n *       Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];\n *       TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));\n *       return (TypeAdapter<T>) newMultisetAdapter(elementAdapter);\n *     }\n *\n *     private <E> TypeAdapter<Multiset<E>> newMultisetAdapter(\n *         final TypeAdapter<E> elementAdapter) {\n *       return new TypeAdapter<Multiset<E>>() {\n *         public void write(JsonWriter out, Multiset<E> value) throws IOException {\n *           if (value == null) {\n *             out.nullValue();\n *             return;\n *           }\n *\n *           out.beginArray();\n *           for (Multiset.Entry<E> entry : value.entrySet()) {\n *             out.value(entry.getCount());\n *             elementAdapter.write(out, entry.getElement());\n *           }\n *           out.endArray();\n *         }\n *\n *         public Multiset<E> read(JsonReader in) throws IOException {\n *           if (in.peek() == JsonToken.NULL) {\n *             in.nextNull();\n *             return null;\n *           }\n *\n *           Multiset<E> result = LinkedHashMultiset.create();\n *           in.beginArray();\n *           while (in.hasNext()) {\n *             int count = in.nextInt();\n *             E element = elementAdapter.read(in);\n *             result.add(element, count);\n *           }\n *           in.endArray();\n *           return result;\n *         }\n *       };\n *     }\n *   }\n * }</pre>\n * Delegating from one type adapter to another is extremely powerful; it's\n * the foundation of how Gson converts Java objects and collections. Whenever\n * possible your factory should retrieve its delegate type adapter in the\n * {@code create()} method; this ensures potentially-expensive type adapter\n * creation happens only once.\n *\n * @since 2.1\n */\npublic interface TypeAdapterFactory {\n\n  /**\n   * Returns a type adapter for {@code type}, or null if this factory doesn't\n   * support {@code type}.\n   */\n  <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type);\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/annotations/Expose.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.GsonBuilder;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * An annotation that indicates this member should be exposed for JSON\n * serialization or deserialization.\n *\n * <p>This annotation has no effect unless you build {@link Gson}\n * with a {@link GsonBuilder} and invoke\n * {@link GsonBuilder#excludeFieldsWithoutExposeAnnotation()}\n * method.</p>\n *\n * <p>Here is an example of how this annotation is meant to be used:\n * <p><pre>\n * public class User {\n *   &#64Expose private String firstName;\n *   &#64Expose(serialize = false) private String lastName;\n *   &#64Expose (serialize = false, deserialize = false) private String emailAddress;\n *   private String password;\n * }\n * </pre></p>\n * If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}\n * methods will use the {@code password} field along-with {@code firstName}, {@code lastName},\n * and {@code emailAddress} for serialization and deserialization. However, if you created Gson\n * with {@code Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()}\n * then the {@code toJson()} and {@code fromJson()} methods of Gson will exclude the\n * {@code password} field. This is because the {@code password} field is not marked with the\n * {@code @Expose} annotation. Gson will also exclude {@code lastName} and {@code emailAddress}\n * from serialization since {@code serialize} is set to {@code false}. Similarly, Gson will\n * exclude {@code emailAddress} from deserialization since {@code deserialize} is set to false.\n *\n * <p>Note that another way to achieve the same effect would have been to just mark the\n * {@code password} field as {@code transient}, and Gson would have excluded it even with default\n * settings. The {@code @Expose} annotation is useful in a style of programming where you want to\n * explicitly specify all fields that should get considered for serialization or deserialization.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.FIELD)\npublic @interface Expose {\n  \n  /**\n   * If {@code true}, the field marked with this annotation is written out in the JSON while\n   * serializing. If {@code false}, the field marked with this annotation is skipped from the\n   * serialized output. Defaults to {@code true}.\n   * @since 1.4\n   */\n  public boolean serialize() default true;\n\n  /**\n   * If {@code true}, the field marked with this annotation is deserialized from the JSON.\n   * If {@code false}, the field marked with this annotation is skipped during deserialization. \n   * Defaults to {@code true}.\n   * @since 1.4\n   */\n  public boolean deserialize() default true;\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/annotations/SerializedName.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.FieldNamingPolicy;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.GsonBuilder;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * An annotation that indicates this member should be serialized to JSON with\n * the provided name value as its field name.\n *\n * <p>This annotation will override any {@link FieldNamingPolicy}, including\n * the default field naming policy, that may have been set on the {@link Gson}\n * instance.  A different naming policy can set using the {@code GsonBuilder} class.  See\n * {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}\n * for more information.</p>\n *\n * <p>Here is an example of how this annotation is meant to be used:</p>\n * <pre>\n * public class SomeClassWithFields {\n *   &#64SerializedName(\"name\") private final String someField;\n *   private final String someOtherField;\n *\n *   public SomeClassWithFields(String a, String b) {\n *     this.someField = a;\n *     this.someOtherField = b;\n *   }\n * }\n * </pre>\n *\n * <p>The following shows the output that is generated when serializing an instance of the\n * above example class:</p>\n * <pre>\n * SomeClassWithFields objectToSerialize = new SomeClassWithFields(\"a\", \"b\");\n * Gson gson = new Gson();\n * String jsonRepresentation = gson.toJson(objectToSerialize);\n * System.out.println(jsonRepresentation);\n *\n * ===== OUTPUT =====\n * {\"name\":\"a\",\"someOtherField\":\"b\"}\n * </pre>\n *\n * <p>NOTE: The value you specify in this annotation must be a valid JSON field name.</p>\n *\n * @see FieldNamingPolicy\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.FIELD)\npublic @interface SerializedName {\n\n  /**\n   * @return the desired name of the field when it is serialized\n   */\n  String value();\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/annotations/Since.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations;\n\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.GsonBuilder;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * An annotation that indicates the version number since a member or a type has been present.\n * This annotation is useful to manage versioning of your Json classes for a web-service.\n *\n * <p>\n * This annotation has no effect unless you build {@link Gson} with a\n * {@link GsonBuilder} and invoke\n * {@link GsonBuilder#setVersion(double)} method.\n *\n * <p>Here is an example of how this annotation is meant to be used:</p>\n * <pre>\n * public class User {\n *   private String firstName;\n *   private String lastName;\n *   &#64Since(1.0) private String emailAddress;\n *   &#64Since(1.0) private String password;\n *   &#64Since(1.1) private Address address;\n * }\n * </pre>\n *\n * <p>If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}\n * methods will use all the fields for serialization and deserialization. However, if you created\n * Gson with {@code Gson gson = new GsonBuilder().setVersion(1.0).create()} then the\n * {@code toJson()} and {@code fromJson()} methods of Gson will exclude the {@code address} field\n * since it's version number is set to {@code 1.1}.</p>\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.FIELD, ElementType.TYPE})\npublic @interface Since {\n  /**\n   * the value indicating a version number since this member\n   * or type has been present.\n   */\n  double value();\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/annotations/Until.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.GsonBuilder;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * An annotation that indicates the version number until a member or a type should be present.\n * Basically, if Gson is created with a version number that exceeds the value stored in the\n * {@code Until} annotation then the field will be ignored from the JSON output.  This annotation\n * is useful to manage versioning of your JSON classes for a web-service.\n *\n * <p>\n * This annotation has no effect unless you build {@link Gson} with a\n * {@link GsonBuilder} and invoke\n * {@link GsonBuilder#setVersion(double)} method.\n *\n * <p>Here is an example of how this annotation is meant to be used:</p>\n * <pre>\n * public class User {\n *   private String firstName;\n *   private String lastName;\n *   &#64Until(1.1) private String emailAddress;\n *   &#64Until(1.1) private String password;\n * }\n * </pre>\n *\n * <p>If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}\n * methods will use all the fields for serialization and deserialization. However, if you created\n * Gson with {@code Gson gson = new GsonBuilder().setVersion(1.2).create()} then the\n * {@code toJson()} and {@code fromJson()} methods of Gson will exclude the {@code emailAddress}\n * and {@code password} fields from the example above, because the version number passed to the \n * GsonBuilder, {@code 1.2}, exceeds the version number set on the {@code Until} annotation,\n * {@code 1.1}, for those fields.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n * @since 1.3\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.FIELD, ElementType.TYPE})\npublic @interface Until {\n\n  /**\n   * the value indicating a version number until this member\n   * or type should be ignored.\n   */\n  double value();\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/annotations/package-info.java",
    "content": "/**\n * This package provides annotations that can be used with {@link com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson}.\n * \n * @author Inderjeet Singh, Joel Leitch\n */\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations;"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/$Gson$Preconditions.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal;\n\n/**\n * A simple utility class used to check method Preconditions.\n *\n * <pre>\n * public long divideBy(long value) {\n *   Preconditions.checkArgument(value != 0);\n *   return this.value / value;\n * }\n * </pre>\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic final class $Gson$Preconditions {\n  public static <T> T checkNotNull(T obj) {\n    if (obj == null) {\n      throw new NullPointerException();\n    }\n    return obj;\n  }\n\n  public static void checkArgument(boolean condition) {\n    if (!condition) {\n      throw new IllegalArgumentException();\n    }\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/$Gson$Types.java",
    "content": "/**\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal;\n\nimport java.io.Serializable;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.GenericArrayType;\nimport java.lang.reflect.GenericDeclaration;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\nimport java.lang.reflect.WildcardType;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.Properties;\n\n/**\n * Static methods for working with types.\n *\n * @author Bob Lee\n * @author Jesse Wilson\n */\npublic final class $Gson$Types {\n  static final Type[] EMPTY_TYPE_ARRAY = new Type[] {};\n\n  private $Gson$Types() {}\n\n  /**\n   * Returns a new parameterized type, applying {@code typeArguments} to\n   * {@code rawType} and enclosed by {@code ownerType}.\n   *\n   * @return a {@link Serializable serializable} parameterized type.\n   */\n  public static ParameterizedType newParameterizedTypeWithOwner(\n          Type ownerType, Type rawType, Type... typeArguments) {\n    return new ParameterizedTypeImpl(ownerType, rawType, typeArguments);\n  }\n\n  /**\n   * Returns an array type whose elements are all instances of\n   * {@code componentType}.\n   *\n   * @return a {@link Serializable serializable} generic array type.\n   */\n  public static GenericArrayType arrayOf(Type componentType) {\n    return new GenericArrayTypeImpl(componentType);\n  }\n\n  /**\n   * Returns a type that represents an unknown type that extends {@code bound}.\n   * For example, if {@code bound} is {@code CharSequence.class}, this returns\n   * {@code ? extends CharSequence}. If {@code bound} is {@code Object.class},\n   * this returns {@code ?}, which is shorthand for {@code ? extends Object}.\n   */\n  public static WildcardType subtypeOf(Type bound) {\n    return new WildcardTypeImpl(new Type[] { bound }, EMPTY_TYPE_ARRAY);\n  }\n\n  /**\n   * Returns a type that represents an unknown supertype of {@code bound}. For\n   * example, if {@code bound} is {@code String.class}, this returns {@code ?\n   * super String}.\n   */\n  public static WildcardType supertypeOf(Type bound) {\n    return new WildcardTypeImpl(new Type[] { Object.class }, new Type[] { bound });\n  }\n\n  /**\n   * Returns a type that is functionally equal but not necessarily equal\n   * according to {@link Object#equals(Object) Object.equals()}. The returned\n   * type is {@link Serializable}.\n   */\n  public static Type canonicalize(Type type) {\n    if (type instanceof Class) {\n      Class<?> c = (Class<?>) type;\n      return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;\n\n    } else if (type instanceof ParameterizedType) {\n      ParameterizedType p = (ParameterizedType) type;\n      return new ParameterizedTypeImpl(p.getOwnerType(),\n          p.getRawType(), p.getActualTypeArguments());\n\n    } else if (type instanceof GenericArrayType) {\n      GenericArrayType g = (GenericArrayType) type;\n      return new GenericArrayTypeImpl(g.getGenericComponentType());\n\n    } else if (type instanceof WildcardType) {\n      WildcardType w = (WildcardType) type;\n      return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds());\n\n    } else {\n      // type is either serializable as-is or unsupported\n      return type;\n    }\n  }\n\n  public static Class<?> getRawType(Type type) {\n    if (type instanceof Class<?>) {\n      // type is a normal class.\n      return (Class<?>) type;\n\n    } else if (type instanceof ParameterizedType) {\n      ParameterizedType parameterizedType = (ParameterizedType) type;\n\n      // I'm not exactly sure why getRawType() returns Type instead of Class.\n      // Neal isn't either but suspects some pathological case related\n      // to nested classes exists.\n      Type rawType = parameterizedType.getRawType();\n      $Gson$Preconditions.checkArgument(rawType instanceof Class);\n      return (Class<?>) rawType;\n\n    } else if (type instanceof GenericArrayType) {\n      Type componentType = ((GenericArrayType)type).getGenericComponentType();\n      return Array.newInstance(getRawType(componentType), 0).getClass();\n\n    } else if (type instanceof TypeVariable) {\n      // we could use the variable's bounds, but that won't work if there are multiple.\n      // having a raw type that's more general than necessary is okay\n      return Object.class;\n\n    } else if (type instanceof WildcardType) {\n      return getRawType(((WildcardType) type).getUpperBounds()[0]);\n\n    } else {\n      String className = type == null ? \"null\" : type.getClass().getName();\n      throw new IllegalArgumentException(\"Expected a Class, ParameterizedType, or \"\n          + \"GenericArrayType, but <\" + type + \"> is of type \" + className);\n    }\n  }\n\n  static boolean equal(Object a, Object b) {\n    return a == b || (a != null && a.equals(b));\n  }\n\n  /**\n   * Returns true if {@code a} and {@code b} are equal.\n   */\n  public static boolean equals(Type a, Type b) {\n    if (a == b) {\n      // also handles (a == null && b == null)\n      return true;\n\n    } else if (a instanceof Class) {\n      // Class already specifies equals().\n      return a.equals(b);\n\n    } else if (a instanceof ParameterizedType) {\n      if (!(b instanceof ParameterizedType)) {\n        return false;\n      }\n\n      // TODO: save a .clone() call\n      ParameterizedType pa = (ParameterizedType) a;\n      ParameterizedType pb = (ParameterizedType) b;\n      return equal(pa.getOwnerType(), pb.getOwnerType())\n          && pa.getRawType().equals(pb.getRawType())\n          && Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments());\n\n    } else if (a instanceof GenericArrayType) {\n      if (!(b instanceof GenericArrayType)) {\n        return false;\n      }\n\n      GenericArrayType ga = (GenericArrayType) a;\n      GenericArrayType gb = (GenericArrayType) b;\n      return equals(ga.getGenericComponentType(), gb.getGenericComponentType());\n\n    } else if (a instanceof WildcardType) {\n      if (!(b instanceof WildcardType)) {\n        return false;\n      }\n\n      WildcardType wa = (WildcardType) a;\n      WildcardType wb = (WildcardType) b;\n      return Arrays.equals(wa.getUpperBounds(), wb.getUpperBounds())\n          && Arrays.equals(wa.getLowerBounds(), wb.getLowerBounds());\n\n    } else if (a instanceof TypeVariable) {\n      if (!(b instanceof TypeVariable)) {\n        return false;\n      }\n      TypeVariable<?> va = (TypeVariable<?>) a;\n      TypeVariable<?> vb = (TypeVariable<?>) b;\n      return va.getGenericDeclaration() == vb.getGenericDeclaration()\n          && va.getName().equals(vb.getName());\n\n    } else {\n      // This isn't a type we support. Could be a generic array type, wildcard type, etc.\n      return false;\n    }\n  }\n\n  private static int hashCodeOrZero(Object o) {\n    return o != null ? o.hashCode() : 0;\n  }\n\n  public static String typeToString(Type type) {\n    return type instanceof Class ? ((Class<?>) type).getName() : type.toString();\n  }\n\n  /**\n   * Returns the generic supertype for {@code supertype}. For example, given a class {@code\n   * IntegerSet}, the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the\n   * result when the supertype is {@code Collection.class} is {@code Collection<Integer>}.\n   */\n  static Type getGenericSupertype(Type context, Class<?> rawType, Class<?> toResolve) {\n    if (toResolve == rawType) {\n      return context;\n    }\n\n    // we skip searching through interfaces if unknown is an interface\n    if (toResolve.isInterface()) {\n      Class<?>[] interfaces = rawType.getInterfaces();\n      for (int i = 0, length = interfaces.length; i < length; i++) {\n        if (interfaces[i] == toResolve) {\n          return rawType.getGenericInterfaces()[i];\n        } else if (toResolve.isAssignableFrom(interfaces[i])) {\n          return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve);\n        }\n      }\n    }\n\n    // check our supertypes\n    if (!rawType.isInterface()) {\n      while (rawType != Object.class) {\n        Class<?> rawSupertype = rawType.getSuperclass();\n        if (rawSupertype == toResolve) {\n          return rawType.getGenericSuperclass();\n        } else if (toResolve.isAssignableFrom(rawSupertype)) {\n          return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve);\n        }\n        rawType = rawSupertype;\n      }\n    }\n\n    // we can't resolve this further\n    return toResolve;\n  }\n\n  /**\n   * Returns the generic form of {@code supertype}. For example, if this is {@code\n   * ArrayList<String>}, this returns {@code Iterable<String>} given the input {@code\n   * Iterable.class}.\n   *\n   * @param supertype a superclass of, or interface implemented by, this.\n   */\n  static Type getSupertype(Type context, Class<?> contextRawType, Class<?> supertype) {\n    $Gson$Preconditions.checkArgument(supertype.isAssignableFrom(contextRawType));\n    return resolve(context, contextRawType,\n        $Gson$Types.getGenericSupertype(context, contextRawType, supertype));\n  }\n\n  /**\n   * Returns the component type of this array type.\n   * @throws ClassCastException if this type is not an array.\n   */\n  public static Type getArrayComponentType(Type array) {\n    return array instanceof GenericArrayType\n        ? ((GenericArrayType) array).getGenericComponentType()\n        : ((Class<?>) array).getComponentType();\n  }\n\n  /**\n   * Returns the element type of this collection type.\n   * @throws IllegalArgumentException if this type is not a collection.\n   */\n  public static Type getCollectionElementType(Type context, Class<?> contextRawType) {\n    Type collectionType = getSupertype(context, contextRawType, Collection.class);\n\n    if (collectionType instanceof WildcardType) {\n      collectionType = ((WildcardType)collectionType).getUpperBounds()[0];\n    }\n    if (collectionType instanceof ParameterizedType) {\n      return ((ParameterizedType) collectionType).getActualTypeArguments()[0];\n    }\n    return Object.class;\n  }\n\n  /**\n   * Returns a two element array containing this map's key and value types in\n   * positions 0 and 1 respectively.\n   */\n  public static Type[] getMapKeyAndValueTypes(Type context, Class<?> contextRawType) {\n    /*\n     * Work around a problem with the declaration of java.util.Properties. That\n     * class should extend Hashtable<String, String>, but it's declared to\n     * extend Hashtable<Object, Object>.\n     */\n    if (context == Properties.class) {\n      return new Type[] { String.class, String.class }; // TODO: test subclasses of Properties!\n    }\n\n    Type mapType = getSupertype(context, contextRawType, Map.class);\n    // TODO: strip wildcards?\n    if (mapType instanceof ParameterizedType) {\n      ParameterizedType mapParameterizedType = (ParameterizedType) mapType;\n      return mapParameterizedType.getActualTypeArguments();\n    }\n    return new Type[] { Object.class, Object.class };\n  }\n\n  public static Type resolve(Type context, Class<?> contextRawType, Type toResolve) {\n    // this implementation is made a little more complicated in an attempt to avoid object-creation\n    while (true) {\n      if (toResolve instanceof TypeVariable) {\n        TypeVariable<?> typeVariable = (TypeVariable<?>) toResolve;\n        toResolve = resolveTypeVariable(context, contextRawType, typeVariable);\n        if (toResolve == typeVariable) {\n          return toResolve;\n        }\n\n      } else if (toResolve instanceof Class && ((Class<?>) toResolve).isArray()) {\n        Class<?> original = (Class<?>) toResolve;\n        Type componentType = original.getComponentType();\n        Type newComponentType = resolve(context, contextRawType, componentType);\n        return componentType == newComponentType\n            ? original\n            : arrayOf(newComponentType);\n\n      } else if (toResolve instanceof GenericArrayType) {\n        GenericArrayType original = (GenericArrayType) toResolve;\n        Type componentType = original.getGenericComponentType();\n        Type newComponentType = resolve(context, contextRawType, componentType);\n        return componentType == newComponentType\n            ? original\n            : arrayOf(newComponentType);\n\n      } else if (toResolve instanceof ParameterizedType) {\n        ParameterizedType original = (ParameterizedType) toResolve;\n        Type ownerType = original.getOwnerType();\n        Type newOwnerType = resolve(context, contextRawType, ownerType);\n        boolean changed = newOwnerType != ownerType;\n\n        Type[] args = original.getActualTypeArguments();\n        for (int t = 0, length = args.length; t < length; t++) {\n          Type resolvedTypeArgument = resolve(context, contextRawType, args[t]);\n          if (resolvedTypeArgument != args[t]) {\n            if (!changed) {\n              args = args.clone();\n              changed = true;\n            }\n            args[t] = resolvedTypeArgument;\n          }\n        }\n\n        return changed\n            ? newParameterizedTypeWithOwner(newOwnerType, original.getRawType(), args)\n            : original;\n\n      } else if (toResolve instanceof WildcardType) {\n        WildcardType original = (WildcardType) toResolve;\n        Type[] originalLowerBound = original.getLowerBounds();\n        Type[] originalUpperBound = original.getUpperBounds();\n\n        if (originalLowerBound.length == 1) {\n          Type lowerBound = resolve(context, contextRawType, originalLowerBound[0]);\n          if (lowerBound != originalLowerBound[0]) {\n            return supertypeOf(lowerBound);\n          }\n        } else if (originalUpperBound.length == 1) {\n          Type upperBound = resolve(context, contextRawType, originalUpperBound[0]);\n          if (upperBound != originalUpperBound[0]) {\n            return subtypeOf(upperBound);\n          }\n        }\n        return original;\n\n      } else {\n        return toResolve;\n      }\n    }\n  }\n\n  static Type resolveTypeVariable(Type context, Class<?> contextRawType, TypeVariable<?> unknown) {\n    Class<?> declaredByRaw = declaringClassOf(unknown);\n\n    // we can't reduce this further\n    if (declaredByRaw == null) {\n      return unknown;\n    }\n\n    Type declaredBy = getGenericSupertype(context, contextRawType, declaredByRaw);\n    if (declaredBy instanceof ParameterizedType) {\n      int index = indexOf(declaredByRaw.getTypeParameters(), unknown);\n      return ((ParameterizedType) declaredBy).getActualTypeArguments()[index];\n    }\n\n    return unknown;\n  }\n\n  private static int indexOf(Object[] array, Object toFind) {\n    for (int i = 0; i < array.length; i++) {\n      if (toFind.equals(array[i])) {\n        return i;\n      }\n    }\n    throw new NoSuchElementException();\n  }\n\n  /**\n   * Returns the declaring class of {@code typeVariable}, or {@code null} if it was not declared by\n   * a class.\n   */\n  private static Class<?> declaringClassOf(TypeVariable<?> typeVariable) {\n    GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();\n    return genericDeclaration instanceof Class\n        ? (Class<?>) genericDeclaration\n        : null;\n  }\n\n  private static void checkNotPrimitive(Type type) {\n    $Gson$Preconditions.checkArgument(!(type instanceof Class<?>) || !((Class<?>) type).isPrimitive());\n  }\n\n  private static final class ParameterizedTypeImpl implements ParameterizedType, Serializable {\n    private final Type ownerType;\n    private final Type rawType;\n    private final Type[] typeArguments;\n\n    public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) {\n      // require an owner type if the raw type needs it\n      if (rawType instanceof Class<?>) {\n        Class<?> rawTypeAsClass = (Class<?>) rawType;\n        $Gson$Preconditions.checkArgument(ownerType != null || rawTypeAsClass.getEnclosingClass() == null);\n        $Gson$Preconditions.checkArgument(ownerType == null || rawTypeAsClass.getEnclosingClass() != null);\n      }\n\n      this.ownerType = ownerType == null ? null : canonicalize(ownerType);\n      this.rawType = canonicalize(rawType);\n      this.typeArguments = typeArguments.clone();\n      for (int t = 0; t < this.typeArguments.length; t++) {\n        $Gson$Preconditions.checkNotNull(this.typeArguments[t]);\n        checkNotPrimitive(this.typeArguments[t]);\n        this.typeArguments[t] = canonicalize(this.typeArguments[t]);\n      }\n    }\n\n    public Type[] getActualTypeArguments() {\n      return typeArguments.clone();\n    }\n\n    public Type getRawType() {\n      return rawType;\n    }\n\n    public Type getOwnerType() {\n      return ownerType;\n    }\n\n    @Override\n    public boolean equals(Object other) {\n      return other instanceof ParameterizedType\n          && $Gson$Types.equals(this, (ParameterizedType) other);\n    }\n\n    @Override\n    public int hashCode() {\n      return Arrays.hashCode(typeArguments)\n          ^ rawType.hashCode()\n          ^ hashCodeOrZero(ownerType);\n    }\n\n    @Override\n    public String toString() {\n      StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1));\n      stringBuilder.append(typeToString(rawType));\n\n      if (typeArguments.length == 0) {\n        return stringBuilder.toString();\n      }\n\n      stringBuilder.append(\"<\").append(typeToString(typeArguments[0]));\n      for (int i = 1; i < typeArguments.length; i++) {\n        stringBuilder.append(\", \").append(typeToString(typeArguments[i]));\n      }\n      return stringBuilder.append(\">\").toString();\n    }\n\n    private static final long serialVersionUID = 0;\n  }\n\n  private static final class GenericArrayTypeImpl implements GenericArrayType, Serializable {\n    private final Type componentType;\n\n    public GenericArrayTypeImpl(Type componentType) {\n      this.componentType = canonicalize(componentType);\n    }\n\n    public Type getGenericComponentType() {\n      return componentType;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n      return o instanceof GenericArrayType\n          && $Gson$Types.equals(this, (GenericArrayType) o);\n    }\n\n    @Override\n    public int hashCode() {\n      return componentType.hashCode();\n    }\n\n    @Override\n    public String toString() {\n      return typeToString(componentType) + \"[]\";\n    }\n\n    private static final long serialVersionUID = 0;\n  }\n\n  /**\n   * The WildcardType interface supports multiple upper bounds and multiple\n   * lower bounds. We only support what the Java 6 language needs - at most one\n   * bound. If a lower bound is set, the upper bound must be Object.class.\n   */\n  private static final class WildcardTypeImpl implements WildcardType, Serializable {\n    private final Type upperBound;\n    private final Type lowerBound;\n\n    public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {\n      $Gson$Preconditions.checkArgument(lowerBounds.length <= 1);\n      $Gson$Preconditions.checkArgument(upperBounds.length == 1);\n\n      if (lowerBounds.length == 1) {\n        $Gson$Preconditions.checkNotNull(lowerBounds[0]);\n        checkNotPrimitive(lowerBounds[0]);\n        $Gson$Preconditions.checkArgument(upperBounds[0] == Object.class);\n        this.lowerBound = canonicalize(lowerBounds[0]);\n        this.upperBound = Object.class;\n\n      } else {\n        $Gson$Preconditions.checkNotNull(upperBounds[0]);\n        checkNotPrimitive(upperBounds[0]);\n        this.lowerBound = null;\n        this.upperBound = canonicalize(upperBounds[0]);\n      }\n    }\n\n    public Type[] getUpperBounds() {\n      return new Type[] { upperBound };\n    }\n\n    public Type[] getLowerBounds() {\n      return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY;\n    }\n\n    @Override\n    public boolean equals(Object other) {\n      return other instanceof WildcardType\n          && $Gson$Types.equals(this, (WildcardType) other);\n    }\n\n    @Override\n    public int hashCode() {\n      // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());\n      return (lowerBound != null ? 31 + lowerBound.hashCode() : 1)\n          ^ (31 + upperBound.hashCode());\n    }\n\n    @Override\n    public String toString() {\n      if (lowerBound != null) {\n        return \"? super \" + typeToString(lowerBound);\n      } else if (upperBound == Object.class) {\n        return \"?\";\n      } else {\n        return \"? extends \" + typeToString(upperBound);\n      }\n    }\n\n    private static final long serialVersionUID = 0;\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/ConstructorConstructor.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.InstanceCreator;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.Map;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\n\n/**\n * Returns a function that can construct an instance of a requested type.\n */\npublic final class ConstructorConstructor {\n  private final Map<Type, InstanceCreator<?>> instanceCreators;\n\n  public ConstructorConstructor(Map<Type, InstanceCreator<?>> instanceCreators) {\n    this.instanceCreators = instanceCreators;\n  }\n\n  public ConstructorConstructor() {\n    this(Collections.<Type, InstanceCreator<?>>emptyMap());\n  }\n\n  public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {\n    final Type type = typeToken.getType();\n    final Class<? super T> rawType = typeToken.getRawType();\n\n    // first try an instance creator\n\n    @SuppressWarnings(\"unchecked\") // types must agree\n    final InstanceCreator<T> creator = (InstanceCreator<T>) instanceCreators.get(type);\n    if (creator != null) {\n      return new ObjectConstructor<T>() {\n        public T construct() {\n          return creator.createInstance(type);\n        }\n      };\n    }\n\n    ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);\n    if (defaultConstructor != null) {\n      return defaultConstructor;\n    }\n\n    ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(rawType);\n    if (defaultImplementation != null) {\n      return defaultImplementation;\n    }\n\n    // finally try unsafe\n    return newUnsafeAllocator(type, rawType);\n  }\n\n  private <T> ObjectConstructor<T> newDefaultConstructor(Class<? super T> rawType) {\n    try {\n      final Constructor<? super T> constructor = rawType.getDeclaredConstructor();\n      if (!constructor.isAccessible()) {\n        constructor.setAccessible(true);\n      }\n      return new ObjectConstructor<T>() {\n        @SuppressWarnings(\"unchecked\") // T is the same raw type as is requested\n        public T construct() {\n          try {\n            Object[] args = null;\n            return (T) constructor.newInstance(args);\n          } catch (InstantiationException e) {\n            // TODO: JsonParseException ?\n            throw new RuntimeException(\"Failed to invoke \" + constructor + \" with no args\", e);\n          } catch (InvocationTargetException e) {\n            // TODO: don't wrap if cause is unchecked!\n            // TODO: JsonParseException ?\n            throw new RuntimeException(\"Failed to invoke \" + constructor + \" with no args\",\n                e.getTargetException());\n          } catch (IllegalAccessException e) {\n            throw new AssertionError(e);\n          }\n        }\n      };\n    } catch (NoSuchMethodException e) {\n      return null;\n    }\n  }\n\n  /**\n   * Constructors for common interface types like Map and List and their\n   * subytpes.\n   */\n  @SuppressWarnings(\"unchecked\") // use runtime checks to guarantee that 'T' is what it is\n  private <T> ObjectConstructor<T> newDefaultImplementationConstructor(Class<? super T> rawType) {\n    if (Collection.class.isAssignableFrom(rawType)) {\n      if (SortedSet.class.isAssignableFrom(rawType)) {\n        return new ObjectConstructor<T>() {\n          public T construct() {\n            return (T) new TreeSet<Object>();\n          }\n        };\n      } else if (Set.class.isAssignableFrom(rawType)) {\n        return new ObjectConstructor<T>() {\n          public T construct() {\n            return (T) new LinkedHashSet<Object>();\n          }\n        };\n      } else if (Queue.class.isAssignableFrom(rawType)) {\n        return new ObjectConstructor<T>() {\n          public T construct() {\n            return (T) new LinkedList<Object>();\n          }\n        };\n      } else {\n        return new ObjectConstructor<T>() {\n          public T construct() {\n            return (T) new ArrayList<Object>();\n          }\n        };\n      }\n    }\n\n    if (Map.class.isAssignableFrom(rawType)) {\n      return new ObjectConstructor<T>() {\n        public T construct() {\n          // TODO: if the map's key type is a string, should this be StringMap?\n          return (T) new LinkedHashMap<Object, Object>();\n        }\n      };\n      // TODO: SortedMap ?\n    }\n\n    return null;\n  }\n\n  private <T> ObjectConstructor<T> newUnsafeAllocator(\n          final Type type, final Class<? super T> rawType) {\n    return new ObjectConstructor<T>() {\n      private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();\n      @SuppressWarnings(\"unchecked\")\n      public T construct() {\n        try {\n          Object newInstance = unsafeAllocator.newInstance(rawType);\n          return (T) newInstance;\n        } catch (Exception e) {\n          throw new RuntimeException((\"Unable to invoke no-args constructor for \" + type + \". \"\n              + \"Register an InstanceCreator with Gson for this type may fix this problem.\"), e);\n        }\n      }\n    };\n  }\n\n  @Override\n  public String toString() {\n    return instanceCreators.toString();\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/Excluder.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.ExclusionStrategy;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.FieldAttributes;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations.Expose;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations.Since;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations.Until;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * This class selects which fields and types to omit. It is configurable,\n * supporting version attributes {@link Since} and {@link Until}, modifiers,\n * synthetic fields, anonymous and local classes, inner classes, and fields with\n * the {@link Expose} annotation.\n *\n * <p>This class is a type adapter factory; types that are excluded will be\n * adapted to null. It may delegate to another type adapter if only one\n * direction is excluded.\n *\n * @author Joel Leitch\n * @author Jesse Wilson\n */\npublic final class Excluder implements TypeAdapterFactory, Cloneable {\n  private static final double IGNORE_VERSIONS = -1.0d;\n  public static final Excluder DEFAULT = new Excluder();\n\n  private double version = IGNORE_VERSIONS;\n  private int modifiers = Modifier.TRANSIENT | Modifier.STATIC;\n  private boolean serializeInnerClasses = true;\n  private boolean requireExpose;\n  private List<ExclusionStrategy> serializationStrategies = Collections.emptyList();\n  private List<ExclusionStrategy> deserializationStrategies = Collections.emptyList();\n\n  @Override\n  protected Excluder clone() {\n    try {\n      return (Excluder) super.clone();\n    } catch (CloneNotSupportedException e) {\n      throw new AssertionError();\n    }\n  }\n\n  public Excluder withVersion(double ignoreVersionsAfter) {\n    Excluder result = clone();\n    result.version = ignoreVersionsAfter;\n    return result;\n  }\n\n  public Excluder withModifiers(int... modifiers) {\n    Excluder result = clone();\n    result.modifiers = 0;\n    for (int modifier : modifiers) {\n      result.modifiers |= modifier;\n    }\n    return result;\n  }\n\n  public Excluder disableInnerClassSerialization() {\n    Excluder result = clone();\n    result.serializeInnerClasses = false;\n    return result;\n  }\n\n  public Excluder excludeFieldsWithoutExposeAnnotation() {\n    Excluder result = clone();\n    result.requireExpose = true;\n    return result;\n  }\n\n  public Excluder withExclusionStrategy(ExclusionStrategy exclusionStrategy,\n      boolean serialization, boolean deserialization) {\n    Excluder result = clone();\n    if (serialization) {\n      result.serializationStrategies = new ArrayList<ExclusionStrategy>(serializationStrategies);\n      result.serializationStrategies.add(exclusionStrategy);\n    }\n    if (deserialization) {\n      result.deserializationStrategies\n          = new ArrayList<ExclusionStrategy>(deserializationStrategies);\n      result.deserializationStrategies.add(exclusionStrategy);\n    }\n    return result;\n  }\n\n  public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {\n    Class<?> rawType = type.getRawType();\n    final boolean skipSerialize = excludeClass(rawType, true);\n    final boolean skipDeserialize = excludeClass(rawType, false);\n\n    if (!skipSerialize && !skipDeserialize) {\n      return null;\n    }\n\n    return new TypeAdapter<T>() {\n      /** The delegate is lazily created because it may not be needed, and creating it may fail. */\n      private TypeAdapter<T> delegate;\n\n      @Override\n      public T read(JsonReader in) throws IOException {\n        if (skipDeserialize) {\n          in.skipValue();\n          return null;\n        }\n        return delegate().read(in);\n      }\n\n      @Override\n      public void write(JsonWriter out, T value) throws IOException {\n        if (skipSerialize) {\n          out.nullValue();\n          return;\n        }\n        delegate().write(out, value);\n      }\n\n      private TypeAdapter<T> delegate() {\n        TypeAdapter<T> d = delegate;\n        return d != null\n            ? d\n            : (delegate = gson.getDelegateAdapter(Excluder.this, type));\n      }\n    };\n  }\n\n  public boolean excludeField(Field field, boolean serialize) {\n    if ((modifiers & field.getModifiers()) != 0) {\n      return true;\n    }\n\n    if (version != Excluder.IGNORE_VERSIONS\n        && !isValidVersion(field.getAnnotation(Since.class), field.getAnnotation(Until.class))) {\n      return true;\n    }\n\n    if (field.isSynthetic()) {\n      return true;\n    }\n\n    if (requireExpose) {\n      Expose annotation = field.getAnnotation(Expose.class);\n      if (annotation == null || (serialize ? !annotation.serialize() : !annotation.deserialize())) {\n        return true;\n      }\n    }\n\n    if (!serializeInnerClasses && isInnerClass(field.getType())) {\n      return true;\n    }\n\n    if (isAnonymousOrLocal(field.getType())) {\n      return true;\n    }\n\n    List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies;\n    if (!list.isEmpty()) {\n      FieldAttributes fieldAttributes = new FieldAttributes(field);\n      for (ExclusionStrategy exclusionStrategy : list) {\n        if (exclusionStrategy.shouldSkipField(fieldAttributes)) {\n          return true;\n        }\n      }\n    }\n\n    return false;\n  }\n\n  public boolean excludeClass(Class<?> clazz, boolean serialize) {\n    if (version != Excluder.IGNORE_VERSIONS\n        && !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class))) {\n      return true;\n    }\n\n    if (!serializeInnerClasses && isInnerClass(clazz)) {\n      return true;\n    }\n\n    if (isAnonymousOrLocal(clazz)) {\n      return true;\n    }\n\n    List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies;\n    for (ExclusionStrategy exclusionStrategy : list) {\n      if (exclusionStrategy.shouldSkipClass(clazz)) {\n        return true;\n      }\n    }\n\n    return false;\n  }\n\n  private boolean isAnonymousOrLocal(Class<?> clazz) {\n    return !Enum.class.isAssignableFrom(clazz)\n        && (clazz.isAnonymousClass() || clazz.isLocalClass());\n  }\n\n  private boolean isInnerClass(Class<?> clazz) {\n    return clazz.isMemberClass() && !isStatic(clazz);\n  }\n\n  private boolean isStatic(Class<?> clazz) {\n    return (clazz.getModifiers() & Modifier.STATIC) != 0;\n  }\n\n  private boolean isValidVersion(Since since, Until until) {\n    return isValidSince(since) && isValidUntil(until);\n  }\n\n  private boolean isValidSince(Since annotation) {\n    if (annotation != null) {\n      double annotationVersion = annotation.value();\n      if (annotationVersion > version) {\n        return false;\n      }\n    }\n    return true;\n  }\n\n  private boolean isValidUntil(Until annotation) {\n    if (annotation != null) {\n      double annotationVersion = annotation.value();\n      if (annotationVersion <= version) {\n        return false;\n      }\n    }\n    return true;\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/JsonReaderInternalAccess.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\n\nimport java.io.IOException;\n\n/**\n * Internal-only APIs of JsonReader available only to other classes in Gson.\n */\npublic abstract class JsonReaderInternalAccess {\n  public static JsonReaderInternalAccess INSTANCE;\n\n  /**\n   * Changes the type of the current property name token to a string value.\n   */\n  public abstract void promoteNameToValue(JsonReader reader) throws IOException;\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/LazilyParsedNumber.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal;\n\nimport java.math.BigInteger;\n\n/**\n * This class holds a number value that is lazily converted to a specific number type\n *\n * @author Inderjeet Singh\n */\n@SuppressWarnings(\"serial\")\npublic final class LazilyParsedNumber extends Number {\n  private final String value;\n\n  public LazilyParsedNumber(String value) {\n    this.value = value;\n  }\n\n  @Override\n  public int intValue() {\n    try {\n      return Integer.parseInt(value);\n    } catch (NumberFormatException e) {\n      try {\n        return (int) Long.parseLong(value);\n      } catch (NumberFormatException nfe) {\n        return new BigInteger(value).intValue();\n      }\n    }\n  }\n\n  @Override\n  public long longValue() {\n    try {\n      return Long.parseLong(value);\n    } catch (NumberFormatException e) {\n      return new BigInteger(value).longValue();\n    }\n  }\n\n  @Override\n  public float floatValue() {\n    return Float.parseFloat(value);\n  }\n\n  @Override\n  public double doubleValue() {\n    return Double.parseDouble(value);\n  }\n\n  @Override\n  public String toString() {\n    return value;\n  }\n}"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/ObjectConstructor.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal;\n\n/**\n * Defines a generic object construction factory.  The purpose of this class\n * is to construct a default instance of a class that can be used for object\n * navigation while deserialization from its JSON representation.\n *\n * @author Inderjeet Singh\n * @author Joel Leitch\n */\npublic interface ObjectConstructor<T> {\n\n  /**\n   * Returns a new instance.\n   */\n  public T construct();\n}"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/Primitives.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal;\n\n\nimport java.lang.reflect.Type;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Contains static utility methods pertaining to primitive types and their\n * corresponding wrapper types.\n *\n * @author Kevin Bourrillion\n */\npublic final class Primitives {\n  private Primitives() {}\n\n  /** A map from primitive types to their corresponding wrapper types. */\n  private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER_TYPE;\n\n  /** A map from wrapper types to their corresponding primitive types. */\n  private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPE;\n\n  // Sad that we can't use a BiMap. :(\n\n  static {\n    Map<Class<?>, Class<?>> primToWrap = new HashMap<Class<?>, Class<?>>(16);\n    Map<Class<?>, Class<?>> wrapToPrim = new HashMap<Class<?>, Class<?>>(16);\n\n    add(primToWrap, wrapToPrim, boolean.class, Boolean.class);\n    add(primToWrap, wrapToPrim, byte.class, Byte.class);\n    add(primToWrap, wrapToPrim, char.class, Character.class);\n    add(primToWrap, wrapToPrim, double.class, Double.class);\n    add(primToWrap, wrapToPrim, float.class, Float.class);\n    add(primToWrap, wrapToPrim, int.class, Integer.class);\n    add(primToWrap, wrapToPrim, long.class, Long.class);\n    add(primToWrap, wrapToPrim, short.class, Short.class);\n    add(primToWrap, wrapToPrim, void.class, Void.class);\n\n    PRIMITIVE_TO_WRAPPER_TYPE = Collections.unmodifiableMap(primToWrap);\n    WRAPPER_TO_PRIMITIVE_TYPE = Collections.unmodifiableMap(wrapToPrim);\n  }\n\n  private static void add(Map<Class<?>, Class<?>> forward,\n                          Map<Class<?>, Class<?>> backward, Class<?> key, Class<?> value) {\n    forward.put(key, value);\n    backward.put(value, key);\n  }\n\n  /**\n   * Returns true if this type is a primitive.\n   */\n  public static boolean isPrimitive(Type type) {\n    return PRIMITIVE_TO_WRAPPER_TYPE.containsKey(type);\n  }\n\n  /**\n   * Returns {@code true} if {@code type} is one of the nine\n   * primitive-wrapper types, such as {@link Integer}.\n   *\n   * @see Class#isPrimitive\n   */\n  public static boolean isWrapperType(Type type) {\n    return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(\n        $Gson$Preconditions.checkNotNull(type));\n  }\n\n  /**\n   * Returns the corresponding wrapper type of {@code type} if it is a primitive\n   * type; otherwise returns {@code type} itself. Idempotent.\n   * <pre>\n   *     wrap(int.class) == Integer.class\n   *     wrap(Integer.class) == Integer.class\n   *     wrap(String.class) == String.class\n   * </pre>\n   */\n  public static <T> Class<T> wrap(Class<T> type) {\n    // cast is safe: long.class and Long.class are both of type Class<Long>\n    @SuppressWarnings(\"unchecked\")\n    Class<T> wrapped = (Class<T>) PRIMITIVE_TO_WRAPPER_TYPE.get(\n        $Gson$Preconditions.checkNotNull(type));\n    return (wrapped == null) ? type : wrapped;\n  }\n\n  /**\n   * Returns the corresponding primitive type of {@code type} if it is a\n   * wrapper type; otherwise returns {@code type} itself. Idempotent.\n   * <pre>\n   *     unwrap(Integer.class) == int.class\n   *     unwrap(int.class) == int.class\n   *     unwrap(String.class) == String.class\n   * </pre>\n   */\n  public static <T> Class<T> unwrap(Class<T> type) {\n    // cast is safe: long.class and Long.class are both of type Class<Long>\n    @SuppressWarnings(\"unchecked\")\n    Class<T> unwrapped = (Class<T>) WRAPPER_TO_PRIMITIVE_TYPE.get(\n        $Gson$Preconditions.checkNotNull(type));\n    return (unwrapped == null) ? type : unwrapped;\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/Streams.java",
    "content": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonElement;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonIOException;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonNull;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonParseException;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonSyntaxException;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.TypeAdapters;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.MalformedJsonException;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.Writer;\n\n/**\n * Reads and writes GSON parse trees over streams.\n */\npublic final class Streams {\n  /**\n   * Takes a reader in any state and returns the next value as a JsonElement.\n   */\n  public static JsonElement parse(JsonReader reader) throws JsonParseException {\n    boolean isEmpty = true;\n    try {\n      reader.peek();\n      isEmpty = false;\n      return TypeAdapters.JSON_ELEMENT.read(reader);\n    } catch (EOFException e) {\n      /*\n       * For compatibility with JSON 1.5 and earlier, we return a JsonNull for\n       * empty documents instead of throwing.\n       */\n      if (isEmpty) {\n        return JsonNull.INSTANCE;\n      }\n      // The stream ended prematurely so it is likely a syntax error.\n      throw new JsonSyntaxException(e);\n    } catch (MalformedJsonException e) {\n      throw new JsonSyntaxException(e);\n    } catch (IOException e) {\n      throw new JsonIOException(e);\n    } catch (NumberFormatException e) {\n      throw new JsonSyntaxException(e);\n    }\n  }\n\n  /**\n   * Writes the JSON element to the writer, recursively.\n   */\n  public static void write(JsonElement element, JsonWriter writer) throws IOException {\n    TypeAdapters.JSON_ELEMENT.write(writer, element);\n  }\n\n  public static Writer writerForAppendable(Appendable appendable) {\n    return appendable instanceof Writer ? (Writer) appendable : new AppendableWriter(appendable);\n  }\n\n  /**\n   * Adapts an {@link Appendable} so it can be passed anywhere a {@link Writer}\n   * is used.\n   */\n  private static class AppendableWriter extends Writer {\n    private final Appendable appendable;\n    private final CurrentWrite currentWrite = new CurrentWrite();\n\n    private AppendableWriter(Appendable appendable) {\n      this.appendable = appendable;\n    }\n\n    @Override\n    public void write(char[] chars, int offset, int length) throws IOException {\n      currentWrite.chars = chars;\n      appendable.append(currentWrite, offset, offset + length);\n    }\n\n    @Override\n    public void write(int i) throws IOException {\n      appendable.append((char) i);\n    }\n\n    @Override\n    public void flush() {}\n    @Override\n    public void close() {}\n\n    /**\n     * A mutable char sequence pointing at a single char[].\n     */\n    static class CurrentWrite implements CharSequence {\n      char[] chars;\n      public int length() {\n        return chars.length;\n      }\n      public char charAt(int i) {\n        return chars[i];\n      }\n      public CharSequence subSequence(int start, int end) {\n        return new String(chars, start, end - start);\n      }\n    }\n  }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/StringMap.java",
    "content": "/*\n *  Licensed to the Apache Software Foundation (ASF) under one or more\n *  contributor license agreements. See the NOTICE file distributed with\n *  this work for additional information regarding copyright ownership.\n *  The ASF licenses this file to You under the Apache License, Version 2.0\n *  (the \"License\"); you may not use this file except in compliance with\n *  the License. You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal;\n\nimport java.util.AbstractCollection;\nimport java.util.AbstractMap;\nimport java.util.AbstractSet;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.Random;\nimport java.util.Set;\n\n/**\n * A map of strings to values. Like LinkedHashMap, this map's iteration order is\n * well defined: it is the order that elements were inserted into the map. This\n * map does not support null keys.\n * \n * <p>This implementation was derived from Android 4.0's LinkedHashMap.\n */\npublic final class StringMap<V> extends AbstractMap<String, V> {\n  /**\n   * Min capacity (other than zero) for a HashMap. Must be a power of two\n   * greater than 1 (and less than 1 << 30).\n   */\n  private static final int MINIMUM_CAPACITY = 4;\n\n  /**\n   * Max capacity for a HashMap. Must be a power of two >= MINIMUM_CAPACITY.\n   */\n  private static final int MAXIMUM_CAPACITY = 1 << 30;\n\n  /**\n   * A dummy entry in the circular linked list of entries in the map.\n   * The first real entry is header.nxt, and the last is header.prv.\n   * If the map is empty, header.nxt == header && header.prv == header.\n   */\n  private LinkedEntry<V> header;\n\n  /**\n   * An empty table shared by all zero-capacity maps (typically from default\n   * constructor). It is never written to, and replaced on first put. Its size\n   * is set to half the minimum, so that the first resize will create a\n   * minimum-sized table.\n   */\n  @SuppressWarnings(\"rawtypes\")\n  private static final Entry[] EMPTY_TABLE = new LinkedEntry[MINIMUM_CAPACITY >>> 1];\n\n  /**\n   * The hash table. If this hash map contains a mapping for null, it is\n   * not represented this hash table.\n   */\n  private LinkedEntry<V>[] table;\n\n  /**\n   * The number of mappings in this hash map.\n   */\n  private int size;\n\n  /**\n   * The table is rehashed when its size exceeds this threshold.\n   * The value of this field is generally .75 * capacity, except when\n   * the capacity is zero, as described in the EMPTY_TABLE declaration\n   * above.\n   */\n  private int threshold;\n\n  // Views - lazily initialized\n  private Set<String> keySet;\n  private Set<Entry<String, V>> entrySet;\n  private Collection<V> values;\n\n  @SuppressWarnings(\"unchecked\")\n  public StringMap() {\n    table = (LinkedEntry<V>[]) EMPTY_TABLE;\n    threshold = -1; // Forces first put invocation to replace EMPTY_TABLE\n    header = new LinkedEntry<V>();\n  }\n\n  @Override\n  public int size() {\n    return size;\n  }\n\n  @Override\n  public boolean containsKey(Object key) {\n    return key instanceof String && getEntry((String) key) != null;\n  }\n\n  @Override\n  public V get(Object key) {\n    if (key instanceof String) {\n      LinkedEntry<V> entry = getEntry((String) key);\n      return entry != null ? entry.value : null;\n    } else {\n      return null;\n    }\n  }\n\n  private LinkedEntry<V> getEntry(String key) {\n    if (key == null) {\n      return null;\n    }\n\n    int hash = hash(key);\n    LinkedEntry<V>[] tab = table;\n    for (LinkedEntry<V> e = tab[hash & (tab.length - 1)]; e != null; e = e.next) {\n      String eKey = e.key;\n      if (eKey == key || (e.hash == hash && key.equals(eKey))) {\n        return e;\n      }\n    }\n    return null;\n  }\n\n  @Override\n  public V put(String key, V value) {\n    if (key == null) {\n      throw new NullPointerException(\"key == null\");\n    }\n\n    int hash = hash(key);\n    LinkedEntry<V>[] tab = table;\n    int index = hash & (tab.length - 1);\n    for (LinkedEntry<V> e = tab[index]; e != null; e = e.next) {\n      if (e.hash == hash && key.equals(e.key)) {\n        V oldValue = e.value;\n        e.value = value;\n        return oldValue;\n      }\n    }\n\n    // No entry for (non-null) key is present; create one\n    if (size++ > threshold) {\n      tab = doubleCapacity();\n      index = hash & (tab.length - 1);\n    }\n    addNewEntry(key, value, hash, index);\n    return null;\n  }\n\n  private void addNewEntry(String key, V value, int hash, int index) {\n    LinkedEntry<V> header = this.header;\n\n    // Create new entry, link it on to list, and put it into table\n    LinkedEntry<V> oldTail = header.prv;\n    LinkedEntry<V> newTail = new LinkedEntry<V>(\n        key, value, hash, table[index], header, oldTail);\n    table[index] = oldTail.nxt = header.prv = newTail;\n  }\n\n  /**\n   * Allocate a table of the given capacity and set the threshold accordingly.\n   * @param newCapacity must be a power of two\n   */\n  private LinkedEntry<V>[] makeTable(int newCapacity) {\n    @SuppressWarnings(\"unchecked\")\n    LinkedEntry<V>[] newTable = (LinkedEntry<V>[]) new LinkedEntry[newCapacity];\n    table = newTable;\n    threshold = (newCapacity >> 1) + (newCapacity >> 2); // 3/4 capacity\n    return newTable;\n  }\n\n  /**\n   * Doubles the capacity of the hash table. Existing entries are placed in\n   * the correct bucket on the enlarged table. If the current capacity is,\n   * MAXIMUM_CAPACITY, this method is a no-op. Returns the table, which\n   * will be new unless we were already at MAXIMUM_CAPACITY.\n   */\n  private LinkedEntry<V>[] doubleCapacity() {\n    LinkedEntry<V>[] oldTable = table;\n    int oldCapacity = oldTable.length;\n    if (oldCapacity == MAXIMUM_CAPACITY) {\n      return oldTable;\n    }\n    int newCapacity = oldCapacity * 2;\n    LinkedEntry<V>[] newTable = makeTable(newCapacity);\n    if (size == 0) {\n      return newTable;\n    }\n\n    for (int j = 0; j < oldCapacity; j++) {\n      /*\n       * Rehash the bucket using the minimum number of field writes.\n       * This is the most subtle and delicate code in the class.\n       */\n      LinkedEntry<V> e = oldTable[j];\n      if (e == null) {\n        continue;\n      }\n      int highBit = e.hash & oldCapacity;\n      LinkedEntry<V> broken = null;\n      newTable[j | highBit] = e;\n      for (LinkedEntry<V> n = e.next; n != null; e = n, n = n.next) {\n        int nextHighBit = n.hash & oldCapacity;\n        if (nextHighBit != highBit) {\n          if (broken == null) {\n            newTable[j | nextHighBit] = n;\n          } else {\n            broken.next = n;\n          }\n          broken = e;\n          highBit = nextHighBit;\n        }\n      }\n      if (broken != null) {\n        broken.next = null;\n      }\n    }\n    return newTable;\n  }\n\n  @Override\n  public V remove(Object key) {\n    if (key == null || !(key instanceof String)) {\n      return null;\n    }\n    int hash = hash((String) key);\n    LinkedEntry<V>[] tab = table;\n    int index = hash & (tab.length - 1);\n    for (LinkedEntry<V> e = tab[index], prev = null;\n        e != null; prev = e, e = e.next) {\n      if (e.hash == hash && key.equals(e.key)) {\n        if (prev == null) {\n          tab[index] = e.next;\n        } else {\n          prev.next = e.next;\n        }\n        size--;\n        unlink(e);\n        return e.value;\n      }\n    }\n    return null;\n  }\n\n  private void unlink(LinkedEntry<V> e) {\n    e.prv.nxt = e.nxt;\n    e.nxt.prv = e.prv;\n    e.nxt = e.prv = null; // Help the GC (for performance)\n  }\n\n  @Override\n  public void clear() {\n    if (size != 0) {\n      Arrays.fill(table, null);\n      size = 0;\n    }\n\n    // Clear all links to help GC\n    LinkedEntry<V> header = this.header;\n    for (LinkedEntry<V> e = header.nxt; e != header; ) {\n      LinkedEntry<V> nxt = e.nxt;\n      e.nxt = e.prv = null;\n      e = nxt;\n    }\n\n    header.nxt = header.prv = header;\n  }\n\n  @Override\n  public Set<String> keySet() {\n    Set<String> ks = keySet;\n    return (ks != null) ? ks : (keySet = new KeySet());\n  }\n\n  @Override\n  public Collection<V> values() {\n    Collection<V> vs = values;\n    return (vs != null) ? vs : (values = new Values());\n  }\n\n  public Set<Entry<String, V>> entrySet() {\n    Set<Entry<String, V>> es = entrySet;\n    return (es != null) ? es : (entrySet = new EntrySet());\n  }\n\n  static class LinkedEntry<V> implements Entry<String, V> {\n    final String key;\n    V value;\n    final int hash;\n    LinkedEntry<V> next;\n    LinkedEntry<V> nxt;\n    LinkedEntry<V> prv;\n\n    /** Create the header entry */\n    LinkedEntry() {\n      this(null, null, 0, null, null, null);\n      nxt = prv = this;\n    }\n\n    LinkedEntry(String key, V value, int hash, LinkedEntry<V> next,\n                LinkedEntry<V> nxt, LinkedEntry<V> prv) {\n      this.key = key;\n      this.value = value;\n      this.hash = hash;\n      this.next = next;\n      this.nxt = nxt;\n      this.prv = prv;\n    }\n\n    public final String getKey() {\n      return key;\n    }\n\n    public final V getValue() {\n      return value;\n    }\n\n    public final V setValue(V value) {\n      V oldValue = this.value;\n      this.value = value;\n      return oldValue;\n    }\n\n    @Override\n    public final boolean equals(Object o) {\n      if (!(o instanceof Map.Entry)) {\n        return false;\n      }\n      Entry<?, ?> e = (Entry<?, ?>) o;\n      Object eValue = e.getValue();\n      return key.equals(e.getKey())\n          && (value == null ? eValue == null : value.equals(eValue));\n    }\n\n    @Override\n    public final int hashCode() {\n      return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());\n    }\n\n    @Override\n    public final String toString() {\n      return key + \"=\" + value;\n    }\n  }\n\n  /**\n   * Removes the mapping from key to value and returns true if this mapping\n   * exists; otherwise, returns does nothing and returns false.\n   */\n  private boolean removeMapping(Object key, Object value) {\n    if (key == null || !(key instanceof String)) {\n      return false;\n    }\n\n    int hash = hash((String) key);\n    LinkedEntry<V>[] tab = table;\n    int index = hash & (tab.length - 1);\n    for (LinkedEntry<V> e = tab[index], prev = null; e != null; prev = e, e = e.next) {\n      if (e.hash == hash && key.equals(e.key)) {\n        if (value == null ? e.value != null : !value.equals(e.value)) {\n          return false;  // Map has wrong value for key\n        }\n        if (prev == null) {\n          tab[index] = e.next;\n        } else {\n          prev.next = e.next;\n        }\n        size--;\n        unlink(e);\n        return true;\n      }\n    }\n    return false; // No entry for key\n  }\n\n  private abstract class LinkedHashIterator<T> implements Iterator<T> {\n    LinkedEntry<V> next = header.nxt;\n    LinkedEntry<V> lastReturned = null;\n\n    public final boolean hasNext() {\n      return next != header;\n    }\n\n    final LinkedEntry<V> nextEntry() {\n      LinkedEntry<V> e = next;\n      if (e == header) {\n        throw new NoSuchElementException();\n      }\n      next = e.nxt;\n      return lastReturned = e;\n    }\n\n    public final void remove() {\n      if (lastReturned == null) {\n        throw new IllegalStateException();\n      }\n      StringMap.this.remove(lastReturned.key);\n      lastReturned = null;\n    }\n  }\n\n  private final class KeySet extends AbstractSet<String> {\n    public Iterator<String> iterator() {\n      return new LinkedHashIterator<String>() {\n        public final String next() {\n          return nextEntry().key;\n        }\n      };\n    }\n\n    public int size() {\n      return size;\n    }\n\n    public boolean contains(Object o) {\n      return containsKey(o);\n    }\n\n    public boolean remove(Object o) {\n      int oldSize = size;\n      StringMap.this.remove(o);\n      return size != oldSize;\n    }\n\n    public void clear() {\n      StringMap.this.clear();\n    }\n  }\n\n  private final class Values extends AbstractCollection<V> {\n    public Iterator<V> iterator() {\n      return new LinkedHashIterator<V>() {\n        public final V next() {\n          return nextEntry().value;\n        }\n      };\n    }\n\n    public int size() {\n      return size;\n    }\n\n    public boolean contains(Object o) {\n      return containsValue(o);\n    }\n\n    public void clear() {\n      StringMap.this.clear();\n    }\n  }\n\n  private final class EntrySet extends AbstractSet<Entry<String, V>> {\n    public Iterator<Entry<String, V>> iterator() {\n      return new LinkedHashIterator<Entry<String, V>>() {\n        public final Entry<String, V> next() {\n          return nextEntry();\n        }\n      };\n    }\n\n    public boolean contains(Object o) {\n      if (!(o instanceof Map.Entry)) {\n        return false;\n      }\n      Entry<?, ?> e = (Entry<?, ?>) o;\n      V mappedValue = get(e.getKey());\n      return mappedValue != null && mappedValue.equals(e.getValue());\n    }\n\n    public boolean remove(Object o) {\n      if (!(o instanceof Map.Entry)) {\n        return false;\n      }\n      Entry<?, ?> e = (Entry<?, ?>) o;\n      return removeMapping(e.getKey(), e.getValue());\n    }\n\n    public int size() {\n      return size;\n    }\n\n    public void clear() {\n      StringMap.this.clear();\n    }\n  }\n\n  private static final int seed = new Random().nextInt();\n  private static int hash(String key) {\n    // Ensuring that the hash is unpredictable and well distributed.\n    //\n    // Finding unpredictable hash functions is a bit of a dark art as we need to balance\n    // good unpredictability (to avoid DoS) and good distribution (for performance).\n    //\n    // We achieve this by using the same algorithm as the Perl version, but this implementation\n    // is being written from scratch by inder who has never seen the\n    // Perl version (for license compliance).\n    //\n    // TODO: investigate http://code.google.com/p/cityhash/ and http://code.google.com/p/smhasher/\n    // both of which may have better distribution and/or unpredictability.\n    int h = seed;\n    for (int i = 0; i < key.length(); ++i) {\n      int h2 = h + key.charAt(i);\n      int h3 = h2 + h2 << 10; // h2 * 1024\n      h = h3 ^ (h3 >>> 6); // h3 / 64\n    }\n\n    /*\n     * Apply Doug Lea's supplemental hash function to avoid collisions for\n     * hashes that do not differ in lower or upper bits.\n     */\n    h ^= (h >>> 20) ^ (h >>> 12);\n    return h ^ (h >>> 7) ^ (h >>> 4);\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/UnsafeAllocator.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal;\n\nimport java.io.ObjectInputStream;\nimport java.io.ObjectStreamClass;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\n/**\n * Do sneaky things to allocate objects without invoking their constructors.\n *\n * @author Joel Leitch\n * @author Jesse Wilson\n */\npublic abstract class UnsafeAllocator {\n  public abstract <T> T newInstance(Class<T> c) throws Exception;\n\n  public static UnsafeAllocator create() {\n    // try JVM\n    // public class Unsafe {\n    //   public Object allocateInstance(Class<?> type);\n    // }\n    try {\n      Class<?> unsafeClass = Class.forName(\"sun.misc.Unsafe\");\n      Field f = unsafeClass.getDeclaredField(\"theUnsafe\");\n      f.setAccessible(true);\n      final Object unsafe = f.get(null);\n      final Method allocateInstance = unsafeClass.getMethod(\"allocateInstance\", Class.class);\n      return new UnsafeAllocator() {\n        @Override\n        @SuppressWarnings(\"unchecked\")\n        public <T> T newInstance(Class<T> c) throws Exception {\n          return (T) allocateInstance.invoke(unsafe, c);\n        }\n      };\n    } catch (Exception ignored) {\n    }\n\n    // try dalvikvm, pre-gingerbread\n    // public class ObjectInputStream {\n    //   private static native Object newInstance(\n    //     Class<?> instantiationClass, Class<?> constructorClass);\n    // }\n    try {\n      final Method newInstance = ObjectInputStream.class\n          .getDeclaredMethod(\"newInstance\", Class.class, Class.class);\n      newInstance.setAccessible(true);\n      return new UnsafeAllocator() {\n        @Override\n        @SuppressWarnings(\"unchecked\")\n        public <T> T newInstance(Class<T> c) throws Exception {\n          return (T) newInstance.invoke(null, c, Object.class);\n        }\n      };\n    } catch (Exception ignored) {\n    }\n\n    // try dalvikvm, post-gingerbread\n    // public class ObjectStreamClass {\n    //   private static native int getConstructorId(Class<?> c);\n    //   private static native Object newInstance(Class<?> instantiationClass, int methodId);\n    // }\n    try {\n      Method getConstructorId = ObjectStreamClass.class\n          .getDeclaredMethod(\"getConstructorId\", Class.class);\n      getConstructorId.setAccessible(true);\n      final int constructorId = (Integer) getConstructorId.invoke(null, Object.class);\n      final Method newInstance = ObjectStreamClass.class\n          .getDeclaredMethod(\"newInstance\", Class.class, int.class);\n      newInstance.setAccessible(true);\n      return new UnsafeAllocator() {\n        @Override\n        @SuppressWarnings(\"unchecked\")\n        public <T> T newInstance(Class<T> c) throws Exception {\n          return (T) newInstance.invoke(null, c, constructorId);\n        }\n      };\n    } catch (Exception ignored) {\n    }\n\n    // give up\n    return new UnsafeAllocator() {\n      @Override\n      public <T> T newInstance(Class<T> c) {\n        throw new UnsupportedOperationException(\"Cannot allocate \" + c);\n      }\n    };\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/bind/ArrayTypeAdapter.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.$Gson$Types;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.GenericArrayType;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Adapt an array of objects.\n */\npublic final class ArrayTypeAdapter<E> extends TypeAdapter<Object> {\n  public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n      Type type = typeToken.getType();\n      if (!(type instanceof GenericArrayType || type instanceof Class && ((Class<?>) type).isArray())) {\n        return null;\n      }\n\n      Type componentType = $Gson$Types.getArrayComponentType(type);\n      TypeAdapter<?> componentTypeAdapter = gson.getAdapter(TypeToken.get(componentType));\n      return new ArrayTypeAdapter(\n              gson, componentTypeAdapter, $Gson$Types.getRawType(componentType));\n    }\n  };\n\n  private final Class<E> componentType;\n  private final TypeAdapter<E> componentTypeAdapter;\n\n  public ArrayTypeAdapter(Gson context, TypeAdapter<E> componentTypeAdapter, Class<E> componentType) {\n    this.componentTypeAdapter =\n      new TypeAdapterRuntimeTypeWrapper<E>(context, componentTypeAdapter, componentType);\n    this.componentType = componentType;\n  }\n\n  public Object read(JsonReader in) throws IOException {\n    if (in.peek() == JsonToken.NULL) {\n      in.nextNull();\n      return null;\n    }\n\n    List<E> list = new ArrayList<E>();\n    in.beginArray();\n    while (in.hasNext()) {\n      E instance = componentTypeAdapter.read(in);\n      list.add(instance);\n    }\n    in.endArray();\n    Object array = Array.newInstance(componentType, list.size());\n    for (int i = 0; i < list.size(); i++) {\n      Array.set(array, i, list.get(i));\n    }\n    return array;\n  }\n\n  @SuppressWarnings(\"unchecked\")\n  @Override\n  public void write(JsonWriter out, Object array) throws IOException {\n    if (array == null) {\n      out.nullValue();\n      return;\n    }\n\n    out.beginArray();\n    for (int i = 0, length = Array.getLength(array); i < length; i++) {\n      E value = (E) Array.get(array, i);\n      componentTypeAdapter.write(out, value);\n    }\n    out.endArray();\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/bind/CollectionTypeAdapterFactory.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.$Gson$Types;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.ConstructorConstructor;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.ObjectConstructor;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.lang.reflect.Type;\nimport java.util.Collection;\n\n/**\n * Adapt a homogeneous collection of objects.\n */\npublic final class CollectionTypeAdapterFactory implements TypeAdapterFactory {\n  private final ConstructorConstructor constructorConstructor;\n\n  public CollectionTypeAdapterFactory(ConstructorConstructor constructorConstructor) {\n    this.constructorConstructor = constructorConstructor;\n  }\n\n  public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n    Type type = typeToken.getType();\n\n    Class<? super T> rawType = typeToken.getRawType();\n    if (!Collection.class.isAssignableFrom(rawType)) {\n      return null;\n    }\n\n    Type elementType = $Gson$Types.getCollectionElementType(type, rawType);\n    TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));\n    ObjectConstructor<T> constructor = constructorConstructor.get(typeToken);\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"}) // create() doesn't define a type parameter\n    TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor);\n    return result;\n  }\n\n  private final class Adapter<E> extends TypeAdapter<Collection<E>> {\n    private final TypeAdapter<E> elementTypeAdapter;\n    private final ObjectConstructor<? extends Collection<E>> constructor;\n\n    public Adapter(Gson context, Type elementType,\n        TypeAdapter<E> elementTypeAdapter,\n        ObjectConstructor<? extends Collection<E>> constructor) {\n      this.elementTypeAdapter =\n          new TypeAdapterRuntimeTypeWrapper<E>(context, elementTypeAdapter, elementType);\n      this.constructor = constructor;\n    }\n\n    public Collection<E> read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n\n      Collection<E> collection = constructor.construct();\n      in.beginArray();\n      while (in.hasNext()) {\n        E instance = elementTypeAdapter.read(in);\n        collection.add(instance);\n      }\n      in.endArray();\n      return collection;\n    }\n\n    public void write(JsonWriter out, Collection<E> collection) throws IOException {\n      if (collection == null) {\n        out.nullValue();\n        return;\n      }\n\n      out.beginArray();\n      for (E element : collection) {\n        elementTypeAdapter.write(out, element);\n      }\n      out.endArray();\n    }\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/bind/DateTypeAdapter.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonSyntaxException;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\nimport java.util.TimeZone;\n\n/**\n * Adapter for Date. Although this class appears stateless, it is not.\n * DateFormat captures its time zone and locale when it is created, which gives\n * this class state. DateFormat isn't thread safe either, so this class has\n * to synchronize its read and write methods.\n */\npublic final class DateTypeAdapter extends TypeAdapter<Date> {\n  public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {\n    @SuppressWarnings(\"unchecked\") // we use a runtime check to make sure the 'T's equal\n    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n      return typeToken.getRawType() == Date.class ? (TypeAdapter<T>) new DateTypeAdapter() : null;\n    }\n  };\n\n  private final DateFormat enUsFormat\n      = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US);\n  private final DateFormat localFormat\n      = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT);\n  private final DateFormat iso8601Format = buildIso8601Format();\n\n  private static DateFormat buildIso8601Format() {\n    DateFormat iso8601Format = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss'Z'\", Locale.US);\n    iso8601Format.setTimeZone(TimeZone.getTimeZone(\"UTC\"));\n    return iso8601Format;\n  }\n\n  @Override\n  public Date read(JsonReader in) throws IOException {\n    if (in.peek() == JsonToken.NULL) {\n      in.nextNull();\n      return null;\n    }\n    return deserializeToDate(in.nextString());\n  }\n\n  private synchronized Date deserializeToDate(String json) {\n    try {\n      return localFormat.parse(json);\n    } catch (ParseException ignored) {\n    }\n    try {\n      return enUsFormat.parse(json);\n    } catch (ParseException ignored) {\n    }\n    try {\n      return iso8601Format.parse(json);\n    } catch (ParseException e) {\n      throw new JsonSyntaxException(json, e);\n    }\n  }\n\n  @Override\n  public synchronized void write(JsonWriter out, Date value) throws IOException {\n    if (value == null) {\n      out.nullValue();\n      return;\n    }\n    String dateFormatAsString = enUsFormat.format(value);\n    out.value(dateFormatAsString);\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/bind/JsonTreeReader.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonArray;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonElement;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonNull;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonObject;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonPrimitive;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * This reader walks the elements of a JsonElement as if it was coming from a\n * character stream.\n *\n * @author Jesse Wilson\n */\npublic final class JsonTreeReader extends JsonReader {\n  private static final Reader UNREADABLE_READER = new Reader() {\n    @Override\n    public int read(char[] buffer, int offset, int count) throws IOException {\n      throw new AssertionError();\n    }\n    @Override\n    public void close() throws IOException {\n      throw new AssertionError();\n    }\n  };\n  private static final Object SENTINEL_CLOSED = new Object();\n\n  private final List<Object> stack = new ArrayList<Object>();\n\n  public JsonTreeReader(JsonElement element) {\n    super(UNREADABLE_READER);\n    stack.add(element);\n  }\n\n  @Override\n  public void beginArray() throws IOException {\n    expect(JsonToken.BEGIN_ARRAY);\n    JsonArray array = (JsonArray) peekStack();\n    stack.add(array.iterator());\n  }\n\n  @Override\n  public void endArray() throws IOException {\n    expect(JsonToken.END_ARRAY);\n    popStack(); // empty iterator\n    popStack(); // array\n  }\n\n  @Override\n  public void beginObject() throws IOException {\n    expect(JsonToken.BEGIN_OBJECT);\n    JsonObject object = (JsonObject) peekStack();\n    stack.add(object.entrySet().iterator());\n  }\n\n  @Override\n  public void endObject() throws IOException {\n    expect(JsonToken.END_OBJECT);\n    popStack(); // empty iterator\n    popStack(); // object\n  }\n\n  @Override\n  public boolean hasNext() throws IOException {\n    JsonToken token = peek();\n    return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY;\n  }\n\n  @Override\n  public JsonToken peek() throws IOException {\n    if (stack.isEmpty()) {\n      return JsonToken.END_DOCUMENT;\n    }\n\n    Object o = peekStack();\n    if (o instanceof Iterator) {\n      boolean isObject = stack.get(stack.size() - 2) instanceof JsonObject;\n      Iterator<?> iterator = (Iterator<?>) o;\n      if (iterator.hasNext()) {\n        if (isObject) {\n          return JsonToken.NAME;\n        } else {\n          stack.add(iterator.next());\n          return peek();\n        }\n      } else {\n        return isObject ? JsonToken.END_OBJECT : JsonToken.END_ARRAY;\n      }\n    } else if (o instanceof JsonObject) {\n      return JsonToken.BEGIN_OBJECT;\n    } else if (o instanceof JsonArray) {\n      return JsonToken.BEGIN_ARRAY;\n    } else if (o instanceof JsonPrimitive) {\n      JsonPrimitive primitive = (JsonPrimitive) o;\n      if (primitive.isString()) {\n        return JsonToken.STRING;\n      } else if (primitive.isBoolean()) {\n        return JsonToken.BOOLEAN;\n      } else if (primitive.isNumber()) {\n        return JsonToken.NUMBER;\n      } else {\n        throw new AssertionError();\n      }\n    } else if (o instanceof JsonNull) {\n      return JsonToken.NULL;\n    } else if (o == SENTINEL_CLOSED) {\n      throw new IllegalStateException(\"JsonReader is closed\");\n    } else {\n      throw new AssertionError();\n    }\n  }\n\n  private Object peekStack() {\n    return stack.get(stack.size() - 1);\n  }\n\n  private Object popStack() {\n    return stack.remove(stack.size() - 1);\n  }\n\n  private void expect(JsonToken expected) throws IOException {\n    if (peek() != expected) {\n      throw new IllegalStateException(\"Expected \" + expected + \" but was \" + peek());\n    }\n  }\n\n  @Override\n  public String nextName() throws IOException {\n    expect(JsonToken.NAME);\n    Iterator<?> i = (Iterator<?>) peekStack();\n    Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next();\n    stack.add(entry.getValue());\n    return (String) entry.getKey();\n  }\n\n  @Override\n  public String nextString() throws IOException {\n    JsonToken token = peek();\n    if (token != JsonToken.STRING && token != JsonToken.NUMBER) {\n      throw new IllegalStateException(\"Expected \" + JsonToken.STRING + \" but was \" + token);\n    }\n    return ((JsonPrimitive) popStack()).getAsString();\n  }\n\n  @Override\n  public boolean nextBoolean() throws IOException {\n    expect(JsonToken.BOOLEAN);\n    return ((JsonPrimitive) popStack()).getAsBoolean();\n  }\n\n  @Override\n  public void nextNull() throws IOException {\n    expect(JsonToken.NULL);\n    popStack();\n  }\n\n  @Override\n  public double nextDouble() throws IOException {\n    JsonToken token = peek();\n    if (token != JsonToken.NUMBER && token != JsonToken.STRING) {\n      throw new IllegalStateException(\"Expected \" + JsonToken.NUMBER + \" but was \" + token);\n    }\n    double result = ((JsonPrimitive) peekStack()).getAsDouble();\n    if (!isLenient() && (Double.isNaN(result) || Double.isInfinite(result))) {\n      throw new NumberFormatException(\"JSON forbids NaN and infinities: \" + result);\n    }\n    popStack();\n    return result;\n  }\n\n  @Override\n  public long nextLong() throws IOException {\n    JsonToken token = peek();\n    if (token != JsonToken.NUMBER && token != JsonToken.STRING) {\n      throw new IllegalStateException(\"Expected \" + JsonToken.NUMBER + \" but was \" + token);\n    }\n    long result = ((JsonPrimitive) peekStack()).getAsLong();\n    popStack();\n    return result;\n  }\n\n  @Override\n  public int nextInt() throws IOException {\n    JsonToken token = peek();\n    if (token != JsonToken.NUMBER && token != JsonToken.STRING) {\n      throw new IllegalStateException(\"Expected \" + JsonToken.NUMBER + \" but was \" + token);\n    }\n    int result = ((JsonPrimitive) peekStack()).getAsInt();\n    popStack();\n    return result;\n  }\n\n  @Override\n  public void close() throws IOException {\n    stack.clear();\n    stack.add(SENTINEL_CLOSED);\n  }\n\n  @Override\n  public void skipValue() throws IOException {\n    if (peek() == JsonToken.NAME) {\n      nextName();\n    } else {\n      popStack();\n    }\n  }\n\n  @Override\n  public String toString() {\n    return getClass().getSimpleName();\n  }\n\n  public void promoteNameToValue() throws IOException {\n    expect(JsonToken.NAME);\n    Iterator<?> i = (Iterator<?>) peekStack();\n    Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next();\n    stack.add(entry.getValue());\n    stack.add(new JsonPrimitive((String)entry.getKey()));\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/bind/JsonTreeWriter.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonArray;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonElement;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonNull;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonObject;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonPrimitive;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * This writer creates a JsonElement.\n */\npublic final class JsonTreeWriter extends JsonWriter {\n  private static final Writer UNWRITABLE_WRITER = new Writer() {\n    @Override\n    public void write(char[] buffer, int offset, int counter) {\n      throw new AssertionError();\n    }\n    @Override\n    public void flush() throws IOException {\n      throw new AssertionError();\n    }\n    @Override\n    public void close() throws IOException {\n      throw new AssertionError();\n    }\n  };\n  /** Added to the top of the stack when this writer is closed to cause following ops to fail. */\n  private static final JsonPrimitive SENTINEL_CLOSED = new JsonPrimitive(\"closed\");\n\n  /** The JsonElements and JsonArrays under modification, outermost to innermost. */\n  private final List<JsonElement> stack = new ArrayList<JsonElement>();\n\n  /** The name for the next JSON object value. If non-null, the top of the stack is a JsonObject. */\n  private String pendingName;\n\n  /** the JSON element constructed by this writer. */\n  private JsonElement product = JsonNull.INSTANCE; // TODO: is this really what we want?;\n\n  public JsonTreeWriter() {\n    super(UNWRITABLE_WRITER);\n  }\n\n  /**\n   * Returns the top level object produced by this writer.\n   */\n  public JsonElement get() {\n    if (!stack.isEmpty()) {\n      throw new IllegalStateException(\"Expected one JSON element but was \" + stack);\n    }\n    return product;\n  }\n\n  private JsonElement peek() {\n    return stack.get(stack.size() - 1);\n  }\n\n  private void put(JsonElement value) {\n    if (pendingName != null) {\n      if (!value.isJsonNull() || getSerializeNulls()) {\n        JsonObject object = (JsonObject) peek();\n        object.add(pendingName, value);\n      }\n      pendingName = null;\n    } else if (stack.isEmpty()) {\n      product = value;\n    } else {\n      JsonElement element = peek();\n      if (element instanceof JsonArray) {\n        ((JsonArray) element).add(value);\n      } else {\n        throw new IllegalStateException();\n      }\n    }\n  }\n\n  @Override\n  public JsonWriter beginArray() throws IOException {\n    JsonArray array = new JsonArray();\n    put(array);\n    stack.add(array);\n    return this;\n  }\n\n  @Override\n  public JsonWriter endArray() throws IOException {\n    if (stack.isEmpty() || pendingName != null) {\n      throw new IllegalStateException();\n    }\n    JsonElement element = peek();\n    if (element instanceof JsonArray) {\n      stack.remove(stack.size() - 1);\n      return this;\n    }\n    throw new IllegalStateException();\n  }\n\n  @Override\n  public JsonWriter beginObject() throws IOException {\n    JsonObject object = new JsonObject();\n    put(object);\n    stack.add(object);\n    return this;\n  }\n\n  @Override\n  public JsonWriter endObject() throws IOException {\n    if (stack.isEmpty() || pendingName != null) {\n      throw new IllegalStateException();\n    }\n    JsonElement element = peek();\n    if (element instanceof JsonObject) {\n      stack.remove(stack.size() - 1);\n      return this;\n    }\n    throw new IllegalStateException();\n  }\n\n  @Override\n  public JsonWriter name(String name) throws IOException {\n    if (stack.isEmpty() || pendingName != null) {\n      throw new IllegalStateException();\n    }\n    JsonElement element = peek();\n    if (element instanceof JsonObject) {\n      pendingName = name;\n      return this;\n    }\n    throw new IllegalStateException();\n  }\n\n  @Override\n  public JsonWriter value(String value) throws IOException {\n    if (value == null) {\n      return nullValue();\n    }\n    put(new JsonPrimitive(value));\n    return this;\n  }\n\n  @Override\n  public JsonWriter nullValue() throws IOException {\n    put(JsonNull.INSTANCE);\n    return this;\n  }\n\n  @Override\n  public JsonWriter value(boolean value) throws IOException {\n    put(new JsonPrimitive(value));\n    return this;\n  }\n\n  @Override\n  public JsonWriter value(double value) throws IOException {\n    if (!isLenient() && (Double.isNaN(value) || Double.isInfinite(value))) {\n      throw new IllegalArgumentException(\"JSON forbids NaN and infinities: \" + value);\n    }\n    put(new JsonPrimitive(value));\n    return this;\n  }\n\n  @Override\n  public JsonWriter value(long value) throws IOException {\n    put(new JsonPrimitive(value));\n    return this;\n  }\n\n  @Override\n  public JsonWriter value(Number value) throws IOException {\n    if (value == null) {\n      return nullValue();\n    }\n\n    if (!isLenient()) {\n      double d = value.doubleValue();\n      if (Double.isNaN(d) || Double.isInfinite(d)) {\n        throw new IllegalArgumentException(\"JSON forbids NaN and infinities: \" + value);\n      }\n    }\n\n    put(new JsonPrimitive(value));\n    return this;\n  }\n\n  @Override\n  public void flush() throws IOException {\n  }\n\n  @Override\n  public void close() throws IOException {\n    if (!stack.isEmpty()) {\n      throw new IOException(\"Incomplete document\");\n    }\n    stack.add(SENTINEL_CLOSED);\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/bind/MapTypeAdapterFactory.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonElement;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonPrimitive;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonSyntaxException;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.$Gson$Types;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.ConstructorConstructor;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.JsonReaderInternalAccess;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.ObjectConstructor;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.Streams;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Adapts maps to either JSON objects or JSON arrays.\n *\n * <h3>Maps as JSON objects</h3>\n * For primitive keys or when complex map key serialization is not enabled, this\n * converts Java {@link Map Maps} to JSON Objects. This requires that map keys\n * can be serialized as strings; this is insufficient for some key types. For\n * example, consider a map whose keys are points on a grid. The default JSON\n * form encodes reasonably: <pre>   {@code\n *   Map<Point, String> original = new LinkedHashMap<Point, String>();\n *   original.put(new Point(5, 6), \"a\");\n *   original.put(new Point(8, 8), \"b\");\n *   System.out.println(gson.toJson(original, type));\n * }</pre>\n * The above code prints this JSON object:<pre>   {@code\n *   {\n *     \"(5,6)\": \"a\",\n *     \"(8,8)\": \"b\"\n *   }\n * }</pre>\n * But GSON is unable to deserialize this value because the JSON string name is\n * just the {@link Object#toString() toString()} of the map key. Attempting to\n * convert the above JSON to an object fails with a parse exception:\n * <pre>com.skynet.google.gson.JsonParseException: Expecting object found: \"(5,6)\"\n *   at com.skynet.google.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler\n *   at com.skynet.google.gson.ObjectNavigator.navigateClassFields\n *   ...</pre>\n *\n * <h3>Maps as JSON arrays</h3>\n * An alternative approach taken by this type adapter when it is required and\n * complex map key serialization is enabled is to encode maps as arrays of map\n * entries. Each map entry is a two element array containing a key and a value.\n * This approach is more flexible because any type can be used as the map's key;\n * not just strings. But it's also less portable because the receiver of such\n * JSON must be aware of the map entry convention.\n *\n * <p>Register this adapter when you are creating your GSON instance.\n * <pre>   {@code\n *   Gson gson = new GsonBuilder()\n *     .registerTypeAdapter(Map.class, new MapAsArrayTypeAdapter())\n *     .create();\n * }</pre>\n * This will change the structure of the JSON emitted by the code above. Now we\n * get an array. In this case the arrays elements are map entries:\n * <pre>   {@code\n *   [\n *     [\n *       {\n *         \"x\": 5,\n *         \"y\": 6\n *       },\n *       \"a\",\n *     ],\n *     [\n *       {\n *         \"x\": 8,\n *         \"y\": 8\n *       },\n *       \"b\"\n *     ]\n *   ]\n * }</pre>\n * This format will serialize and deserialize just fine as long as this adapter\n * is registered.\n */\npublic final class MapTypeAdapterFactory implements TypeAdapterFactory {\n  private final ConstructorConstructor constructorConstructor;\n  private final boolean complexMapKeySerialization;\n\n  public MapTypeAdapterFactory(ConstructorConstructor constructorConstructor,\n      boolean complexMapKeySerialization) {\n    this.constructorConstructor = constructorConstructor;\n    this.complexMapKeySerialization = complexMapKeySerialization;\n  }\n\n  public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n    Type type = typeToken.getType();\n\n    Class<? super T> rawType = typeToken.getRawType();\n    if (!Map.class.isAssignableFrom(rawType)) {\n      return null;\n    }\n\n    Class<?> rawTypeOfSrc = $Gson$Types.getRawType(type);\n    Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(type, rawTypeOfSrc);\n    TypeAdapter<?> keyAdapter = getKeyAdapter(gson, keyAndValueTypes[0]);\n    TypeAdapter<?> valueAdapter = gson.getAdapter(TypeToken.get(keyAndValueTypes[1]));\n    ObjectConstructor<T> constructor = constructorConstructor.get(typeToken);\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    // we don't define a type parameter for the key or value types\n    TypeAdapter<T> result = new Adapter(gson, keyAndValueTypes[0], keyAdapter,\n        keyAndValueTypes[1], valueAdapter, constructor);\n    return result;\n  }\n\n  /**\n   * Returns a type adapter that writes the value as a string.\n   */\n  private TypeAdapter<?> getKeyAdapter(Gson context, Type keyType) {\n    return (keyType == boolean.class || keyType == Boolean.class)\n        ? TypeAdapters.BOOLEAN_AS_STRING\n        : context.getAdapter(TypeToken.get(keyType));\n  }\n\n  private final class Adapter<K, V> extends TypeAdapter<Map<K, V>> {\n    private final TypeAdapter<K> keyTypeAdapter;\n    private final TypeAdapter<V> valueTypeAdapter;\n    private final ObjectConstructor<? extends Map<K, V>> constructor;\n\n    public Adapter(Gson context, Type keyType, TypeAdapter<K> keyTypeAdapter,\n                   Type valueType, TypeAdapter<V> valueTypeAdapter,\n                   ObjectConstructor<? extends Map<K, V>> constructor) {\n      this.keyTypeAdapter =\n        new TypeAdapterRuntimeTypeWrapper<K>(context, keyTypeAdapter, keyType);\n      this.valueTypeAdapter =\n        new TypeAdapterRuntimeTypeWrapper<V>(context, valueTypeAdapter, valueType);\n      this.constructor = constructor;\n    }\n\n    public Map<K, V> read(JsonReader in) throws IOException {\n      JsonToken peek = in.peek();\n      if (peek == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n\n      Map<K, V> map = constructor.construct();\n\n      if (peek == JsonToken.BEGIN_ARRAY) {\n        in.beginArray();\n        while (in.hasNext()) {\n          in.beginArray(); // entry array\n          K key = keyTypeAdapter.read(in);\n          V value = valueTypeAdapter.read(in);\n          V replaced = map.put(key, value);\n          if (replaced != null) {\n            throw new JsonSyntaxException(\"duplicate key: \" + key);\n          }\n          in.endArray();\n        }\n        in.endArray();\n      } else {\n        in.beginObject();\n        while (in.hasNext()) {\n          JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in);\n          K key = keyTypeAdapter.read(in);\n          V value = valueTypeAdapter.read(in);\n          V replaced = map.put(key, value);\n          if (replaced != null) {\n            throw new JsonSyntaxException(\"duplicate key: \" + key);\n          }\n        }\n        in.endObject();\n      }\n      return map;\n    }\n\n    public void write(JsonWriter out, Map<K, V> map) throws IOException {\n      if (map == null) {\n        out.nullValue();\n        return;\n      }\n\n      if (!complexMapKeySerialization) {\n        out.beginObject();\n        for (Map.Entry<K, V> entry : map.entrySet()) {\n          out.name(String.valueOf(entry.getKey()));\n          valueTypeAdapter.write(out, entry.getValue());\n        }\n        out.endObject();\n        return;\n      }\n\n      boolean hasComplexKeys = false;\n      List<JsonElement> keys = new ArrayList<JsonElement>(map.size());\n\n      List<V> values = new ArrayList<V>(map.size());\n      for (Map.Entry<K, V> entry : map.entrySet()) {\n        JsonElement keyElement = keyTypeAdapter.toJsonTree(entry.getKey());\n        keys.add(keyElement);\n        values.add(entry.getValue());\n        hasComplexKeys |= keyElement.isJsonArray() || keyElement.isJsonObject();\n      }\n\n      if (hasComplexKeys) {\n        out.beginArray();\n        for (int i = 0; i < keys.size(); i++) {\n          out.beginArray(); // entry array\n          Streams.write(keys.get(i), out);\n          valueTypeAdapter.write(out, values.get(i));\n          out.endArray();\n        }\n        out.endArray();\n      } else {\n        out.beginObject();\n        for (int i = 0; i < keys.size(); i++) {\n          JsonElement keyElement = keys.get(i);\n          out.name(keyToString(keyElement));\n          valueTypeAdapter.write(out, values.get(i));\n        }\n        out.endObject();\n      }\n    }\n\n    private String keyToString(JsonElement keyElement) {\n      if (keyElement.isJsonPrimitive()) {\n        JsonPrimitive primitive = keyElement.getAsJsonPrimitive();\n        if (primitive.isNumber()) {\n          return String.valueOf(primitive.getAsNumber());\n        } else if (primitive.isBoolean()) {\n          return Boolean.toString(primitive.getAsBoolean());\n        } else if (primitive.isString()) {\n          return primitive.getAsString();\n        } else {\n          throw new AssertionError();\n        }\n      } else if (keyElement.isJsonNull()) {\n        return \"null\";\n      } else {\n        throw new AssertionError();\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/bind/ObjectTypeAdapter.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.StringMap;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Adapts types whose static type is only 'Object'. Uses getClass() on\n * serialization and a primitive/Map/List on deserialization.\n */\npublic final class ObjectTypeAdapter extends TypeAdapter<Object> {\n  public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {\n    @SuppressWarnings(\"unchecked\")\n    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {\n      if (type.getRawType() == Object.class) {\n        return (TypeAdapter<T>) new ObjectTypeAdapter(gson);\n      }\n      return null;\n    }\n  };\n\n  private final Gson gson;\n\n  private ObjectTypeAdapter(Gson gson) {\n    this.gson = gson;\n  }\n\n  @Override\n  public Object read(JsonReader in) throws IOException {\n    JsonToken token = in.peek();\n    switch (token) {\n    case BEGIN_ARRAY:\n      List<Object> list = new ArrayList<Object>();\n      in.beginArray();\n      while (in.hasNext()) {\n        list.add(read(in));\n      }\n      in.endArray();\n      return list;\n\n    case BEGIN_OBJECT:\n      Map<String, Object> map = new StringMap<Object>();\n      in.beginObject();\n      while (in.hasNext()) {\n        map.put(in.nextName(), read(in));\n      }\n      in.endObject();\n      return map;\n\n    case STRING:\n      return in.nextString();\n\n    case NUMBER:\n      return in.nextDouble();\n\n    case BOOLEAN:\n      return in.nextBoolean();\n\n    case NULL:\n      in.nextNull();\n      return null;\n\n    }\n    throw new IllegalStateException();\n  }\n\n  @SuppressWarnings(\"unchecked\")\n  @Override\n  public void write(JsonWriter out, Object value) throws IOException {\n    if (value == null) {\n      out.nullValue();\n      return;\n    }\n\n    TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) gson.getAdapter(value.getClass());\n    if (typeAdapter instanceof ObjectTypeAdapter) {\n      out.beginObject();\n      out.endObject();\n      return;\n    }\n\n    typeAdapter.write(out, value);\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.FieldNamingStrategy;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonSyntaxException;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations.SerializedName;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.$Gson$Types;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.ConstructorConstructor;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.Excluder;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.ObjectConstructor;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.Primitives;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Type;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * Type adapter that reflects over the fields and methods of a class.\n */\npublic final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {\n  private final ConstructorConstructor constructorConstructor;\n  private final FieldNamingStrategy fieldNamingPolicy;\n  private final Excluder excluder;\n\n  public ReflectiveTypeAdapterFactory(ConstructorConstructor constructorConstructor,\n      FieldNamingStrategy fieldNamingPolicy, Excluder excluder) {\n    this.constructorConstructor = constructorConstructor;\n    this.fieldNamingPolicy = fieldNamingPolicy;\n    this.excluder = excluder;\n  }\n\n  public boolean excludeField(Field f, boolean serialize) {\n    return !excluder.excludeClass(f.getType(), serialize) && !excluder.excludeField(f, serialize);\n  }\n\n  private String getFieldName(Field f) {\n    SerializedName serializedName = f.getAnnotation(SerializedName.class);\n    return serializedName == null ? fieldNamingPolicy.translateName(f) : serializedName.value();\n  }\n\n  public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {\n    Class<? super T> raw = type.getRawType();\n\n    if (!Object.class.isAssignableFrom(raw)) {\n      return null; // it's a primitive!\n    }\n\n    ObjectConstructor<T> constructor = constructorConstructor.get(type);\n    return new Adapter<T>(constructor, getBoundFields(gson, type, raw));\n  }\n\n  private BoundField createBoundField(\n          final Gson context, final Field field, final String name,\n          final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {\n    final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());\n\n    // special casing primitives here saves ~5% on Android...\n    return new BoundField(name, serialize, deserialize) {\n      final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType);\n      @SuppressWarnings({\"unchecked\", \"rawtypes\"}) // the type adapter and field type always agree\n      @Override\n      void write(JsonWriter writer, Object value)\n          throws IOException, IllegalAccessException {\n        Object fieldValue = field.get(value);\n        TypeAdapter t =\n          new TypeAdapterRuntimeTypeWrapper(context, this.typeAdapter, fieldType.getType());\n        t.write(writer, fieldValue);\n      }\n      @Override\n      void read(JsonReader reader, Object value)\n          throws IOException, IllegalAccessException {\n        Object fieldValue = typeAdapter.read(reader);\n        if (fieldValue != null || !isPrimitive) {\n          field.set(value, fieldValue);\n        }\n      }\n    };\n  }\n\n  private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {\n    Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();\n    if (raw.isInterface()) {\n      return result;\n    }\n\n    Type declaredType = type.getType();\n    while (raw != Object.class) {\n      Field[] fields = raw.getDeclaredFields();\n      for (Field field : fields) {\n        boolean serialize = excludeField(field, true);\n        boolean deserialize = excludeField(field, false);\n        if (!serialize && !deserialize) {\n          continue;\n        }\n        field.setAccessible(true);\n        Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());\n        BoundField boundField = createBoundField(context, field, getFieldName(field),\n            TypeToken.get(fieldType), serialize, deserialize);\n        BoundField previous = result.put(boundField.name, boundField);\n        if (previous != null) {\n          throw new IllegalArgumentException(declaredType\n              + \" declares multiple JSON fields named \" + previous.name);\n        }\n      }\n      type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));\n      raw = type.getRawType();\n    }\n    return result;\n  }\n\n  static abstract class BoundField {\n    final String name;\n    final boolean serialized;\n    final boolean deserialized;\n\n    protected BoundField(String name, boolean serialized, boolean deserialized) {\n      this.name = name;\n      this.serialized = serialized;\n      this.deserialized = deserialized;\n    }\n\n    abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;\n    abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;\n  }\n\n  public final class Adapter<T> extends TypeAdapter<T> {\n    private final ObjectConstructor<T> constructor;\n    private final Map<String, BoundField> boundFields;\n\n    private Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) {\n      this.constructor = constructor;\n      this.boundFields = boundFields;\n    }\n\n    @Override\n    public T read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n\n      T instance = constructor.construct();\n\n      try {\n        in.beginObject();\n        while (in.hasNext()) {\n          String name = in.nextName();\n          BoundField field = boundFields.get(name);\n          if (field == null || !field.deserialized) {\n            in.skipValue();\n          } else {\n            field.read(in, instance);\n          }\n        }\n      } catch (IllegalStateException e) {\n        throw new JsonSyntaxException(e);\n      } catch (IllegalAccessException e) {\n        throw new AssertionError(e);\n      }\n      in.endObject();\n      return instance;\n    }\n\n    @Override\n    public void write(JsonWriter out, T value) throws IOException {\n      if (value == null) {\n        out.nullValue();\n        return;\n      }\n\n      out.beginObject();\n      try {\n        for (BoundField boundField : boundFields.values()) {\n          if (boundField.serialized) {\n            out.name(boundField.name);\n            boundField.write(out, value);\n          }\n        }\n      } catch (IllegalAccessException e) {\n        throw new AssertionError();\n      }\n      out.endObject();\n    }\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/bind/SqlDateTypeAdapter.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonSyntaxException;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.sql.Date;\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\n\n/**\n * Adapter for java.sql.Date. Although this class appears stateless, it is not.\n * DateFormat captures its time zone and locale when it is created, which gives\n * this class state. DateFormat isn't thread safe either, so this class has\n * to synchronize its read and write methods.\n */\npublic final class SqlDateTypeAdapter extends TypeAdapter<Date> {\n  public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {\n    @SuppressWarnings(\"unchecked\") // we use a runtime check to make sure the 'T's equal\n    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n      return typeToken.getRawType() == Date.class\n          ? (TypeAdapter<T>) new SqlDateTypeAdapter() : null;\n    }\n  };\n\n  private final DateFormat format = new SimpleDateFormat(\"MMM d, yyyy\");\n\n  @Override\n  public synchronized Date read(JsonReader in) throws IOException {\n    if (in.peek() == JsonToken.NULL) {\n      in.nextNull();\n      return null;\n    }\n    try {\n      final long utilDate = format.parse(in.nextString()).getTime();\n      return new Date(utilDate);\n    } catch (ParseException e) {\n      throw new JsonSyntaxException(e);\n    }\n  }\n\n  @Override\n  public synchronized void write(JsonWriter out, Date value) throws IOException {\n    out.value(value == null ? null : format.format(value));\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/bind/TimeTypeAdapter.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonSyntaxException;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.sql.Time;\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * Adapter for Time. Although this class appears stateless, it is not.\n * DateFormat captures its time zone and locale when it is created, which gives\n * this class state. DateFormat isn't thread safe either, so this class has\n * to synchronize its read and write methods.\n */\npublic final class TimeTypeAdapter extends TypeAdapter<Time> {\n  public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {\n    @SuppressWarnings(\"unchecked\") // we use a runtime check to make sure the 'T's equal\n    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n      return typeToken.getRawType() == Time.class ? (TypeAdapter<T>) new TimeTypeAdapter() : null;\n    }\n  };\n\n  private final DateFormat format = new SimpleDateFormat(\"hh:mm:ss a\");\n\n  @Override\n  public synchronized Time read(JsonReader in) throws IOException {\n    if (in.peek() == JsonToken.NULL) {\n      in.nextNull();\n      return null;\n    }\n    try {\n      Date date = format.parse(in.nextString());\n      return new Time(date.getTime());\n    } catch (ParseException e) {\n      throw new JsonSyntaxException(e);\n    }\n  }\n\n  @Override\n  public synchronized void write(JsonWriter out, Time value) throws IOException {\n    out.value(value == null ? null : format.format(value));\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/bind/TypeAdapterRuntimeTypeWrapper.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\n\nfinal class TypeAdapterRuntimeTypeWrapper<T> extends TypeAdapter<T> {\n  private final Gson context;\n  private final TypeAdapter<T> delegate;\n  private final Type type;\n\n  TypeAdapterRuntimeTypeWrapper(Gson context, TypeAdapter<T> delegate, Type type) {\n    this.context = context;\n    this.delegate = delegate;\n    this.type = type;\n  }\n\n  @Override\n  public T read(JsonReader in) throws IOException {\n    return delegate.read(in);\n  }\n\n  @SuppressWarnings({\"rawtypes\", \"unchecked\"})\n  @Override\n  public void write(JsonWriter out, T value) throws IOException {\n    // Order of preference for choosing type adapters\n    // First preference: a type adapter registered for the runtime type\n    // Second preference: a type adapter registered for the declared type\n    // Third preference: reflective type adapter for the runtime type (if it is a sub class of the declared type)\n    // Fourth preference: reflective type adapter for the declared type\n\n    TypeAdapter chosen = delegate;\n    Type runtimeType = getRuntimeTypeIfMoreSpecific(type, value);\n    if (runtimeType != type) {\n      TypeAdapter runtimeTypeAdapter = context.getAdapter(TypeToken.get(runtimeType));\n      if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter)) {\n        // The user registered a type adapter for the runtime type, so we will use that\n        chosen = runtimeTypeAdapter;\n      } else if (!(delegate instanceof ReflectiveTypeAdapterFactory.Adapter)) {\n        // The user registered a type adapter for Base class, so we prefer it over the\n        // reflective type adapter for the runtime type\n        chosen = delegate;\n      } else {\n        // Use the type adapter for runtime type\n        chosen = runtimeTypeAdapter;\n      }\n    }\n    chosen.write(out, value);\n  }\n\n  /**\n   * Finds a compatible runtime type if it is more specific\n   */\n  private Type getRuntimeTypeIfMoreSpecific(Type type, Object value) {\n    if (value != null\n        && (type == Object.class || type instanceof TypeVariable<?> || type instanceof Class<?>)) {\n      type = value.getClass();\n    }\n    return type;\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/bind/TypeAdapters.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonArray;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonElement;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonIOException;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonNull;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonObject;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonPrimitive;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.JsonSyntaxException;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.TypeAdapterFactory;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.annotations.SerializedName;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.LazilyParsedNumber;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect.TypeToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonReader;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonToken;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.stream.JsonWriter;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.InetAddress;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.sql.Timestamp;\nimport java.util.BitSet;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.GregorianCalendar;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.StringTokenizer;\n\n/**\n * Type adapters for basic types.\n */\npublic final class TypeAdapters {\n  private TypeAdapters() {}\n\n  @SuppressWarnings(\"rawtypes\")\n  public static final TypeAdapter<Class> CLASS = new TypeAdapter<Class>() {\n    @Override\n    public void write(JsonWriter out, Class value) throws IOException {\n      throw new UnsupportedOperationException(\"Attempted to serialize java.lang.Class: \"\n          + value.getName() + \". Forgot to register a type adapter?\");\n    }\n    @Override\n    public Class read(JsonReader in) throws IOException {\n        throw new UnsupportedOperationException(\n            \"Attempted to deserialize a java.lang.Class. Forgot to register a type adapter?\");\n    }\n  };\n  public static final TypeAdapterFactory CLASS_FACTORY = newFactory(Class.class, CLASS);\n\n  public static final TypeAdapter<BitSet> BIT_SET = new TypeAdapter<BitSet>() {\n    public BitSet read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n\n      BitSet bitset = new BitSet();\n      in.beginArray();\n      int i = 0;\n      JsonToken tokenType = in.peek();\n      while (tokenType != JsonToken.END_ARRAY) {\n        boolean set;\n        switch (tokenType) {\n        case NUMBER:\n          set = in.nextInt() != 0;\n          break;\n        case BOOLEAN:\n          set = in.nextBoolean();\n          break;\n        case STRING:\n          String stringValue = in.nextString();\n          try {\n            set = Integer.parseInt(stringValue) != 0;\n          } catch (NumberFormatException e) {\n            throw new JsonSyntaxException(\n                \"Error: Expecting: bitset number value (1, 0), Found: \" + stringValue);\n          }\n          break;\n        default:\n          throw new JsonSyntaxException(\"Invalid bitset value type: \" + tokenType);\n        }\n        if (set) {\n          bitset.set(i);\n        }\n        ++i;\n        tokenType = in.peek();\n      }\n      in.endArray();\n      return bitset;\n    }\n\n    public void write(JsonWriter out, BitSet src) throws IOException {\n      if (src == null) {\n        out.nullValue();\n        return;\n      }\n\n      out.beginArray();\n      for (int i = 0; i < src.length(); i++) {\n        int value = (src.get(i)) ? 1 : 0;\n        out.value(value);\n      }\n      out.endArray();\n    }\n  };\n\n  public static final TypeAdapterFactory BIT_SET_FACTORY = newFactory(BitSet.class, BIT_SET);\n\n  public static final TypeAdapter<Boolean> BOOLEAN = new TypeAdapter<Boolean>() {\n    @Override\n    public Boolean read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      } else if (in.peek() == JsonToken.STRING) {\n        // support strings for compatibility with GSON 1.7\n        return Boolean.parseBoolean(in.nextString());\n      }\n      return in.nextBoolean();\n    }\n    @Override\n    public void write(JsonWriter out, Boolean value) throws IOException {\n      if (value == null) {\n        out.nullValue();\n        return;\n      }\n      out.value(value);\n    }\n  };\n\n  /**\n   * Writes a boolean as a string. Useful for map keys, where booleans aren't\n   * otherwise permitted.\n   */\n  public static final TypeAdapter<Boolean> BOOLEAN_AS_STRING = new TypeAdapter<Boolean>() {\n    @Override\n    public Boolean read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      return Boolean.valueOf(in.nextString());\n    }\n\n    @Override\n    public void write(JsonWriter out, Boolean value) throws IOException {\n      out.value(value == null ? \"null\" : value.toString());\n    }\n  };\n\n  public static final TypeAdapterFactory BOOLEAN_FACTORY\n      = newFactory(boolean.class, Boolean.class, BOOLEAN);\n\n  public static final TypeAdapter<Number> BYTE = new TypeAdapter<Number>() {\n    @Override\n    public Number read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      try {\n        int intValue = in.nextInt();\n        return (byte) intValue;\n      } catch (NumberFormatException e) {\n        throw new JsonSyntaxException(e);\n      }\n    }\n    @Override\n    public void write(JsonWriter out, Number value) throws IOException {\n      out.value(value);\n    }\n  };\n\n  public static final TypeAdapterFactory BYTE_FACTORY\n      = newFactory(byte.class, Byte.class, BYTE);\n\n  public static final TypeAdapter<Number> SHORT = new TypeAdapter<Number>() {\n    @Override\n    public Number read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      try {\n        return (short) in.nextInt();\n      } catch (NumberFormatException e) {\n        throw new JsonSyntaxException(e);\n      }\n    }\n    @Override\n    public void write(JsonWriter out, Number value) throws IOException {\n      out.value(value);\n    }\n  };\n\n  public static final TypeAdapterFactory SHORT_FACTORY\n      = newFactory(short.class, Short.class, SHORT);\n\n  public static final TypeAdapter<Number> INTEGER = new TypeAdapter<Number>() {\n    @Override\n    public Number read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      try {\n        return in.nextInt();\n      } catch (NumberFormatException e) {\n        throw new JsonSyntaxException(e);\n      }\n    }\n    @Override\n    public void write(JsonWriter out, Number value) throws IOException {\n      out.value(value);\n    }\n  };\n\n  public static final TypeAdapterFactory INTEGER_FACTORY\n      = newFactory(int.class, Integer.class, INTEGER);\n\n  public static final TypeAdapter<Number> LONG = new TypeAdapter<Number>() {\n    @Override\n    public Number read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      try {\n        return in.nextLong();\n      } catch (NumberFormatException e) {\n        throw new JsonSyntaxException(e);\n      }\n    }\n    @Override\n    public void write(JsonWriter out, Number value) throws IOException {\n      out.value(value);\n    }\n  };\n\n  public static final TypeAdapter<Number> FLOAT = new TypeAdapter<Number>() {\n    @Override\n    public Number read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      return (float) in.nextDouble();\n    }\n    @Override\n    public void write(JsonWriter out, Number value) throws IOException {\n      out.value(value);\n    }\n  };\n\n  public static final TypeAdapter<Number> DOUBLE = new TypeAdapter<Number>() {\n    @Override\n    public Number read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      return in.nextDouble();\n    }\n    @Override\n    public void write(JsonWriter out, Number value) throws IOException {\n      out.value(value);\n    }\n  };\n\n  public static final TypeAdapter<Number> NUMBER = new TypeAdapter<Number>() {\n    @Override\n    public Number read(JsonReader in) throws IOException {\n      JsonToken jsonToken = in.peek();\n      switch (jsonToken) {\n      case NULL:\n        in.nextNull();\n        return null;\n      case NUMBER:\n        return new LazilyParsedNumber(in.nextString());\n      default:\n        throw new JsonSyntaxException(\"Expecting number, got: \" + jsonToken);\n      }\n    }\n    @Override\n    public void write(JsonWriter out, Number value) throws IOException {\n      out.value(value);\n    }\n  };\n\n  public static final TypeAdapterFactory NUMBER_FACTORY = newFactory(Number.class, NUMBER);\n\n  public static final TypeAdapter<Character> CHARACTER = new TypeAdapter<Character>() {\n    @Override\n    public Character read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      String str = in.nextString();\n      if (str.length() != 1) {\n        throw new JsonSyntaxException(\"Expecting character, got: \" + str);\n      }\n      return str.charAt(0);\n    }\n    @Override\n    public void write(JsonWriter out, Character value) throws IOException {\n      out.value(value == null ? null : String.valueOf(value));\n    }\n  };\n\n  public static final TypeAdapterFactory CHARACTER_FACTORY\n      = newFactory(char.class, Character.class, CHARACTER);\n\n  public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {\n    @Override\n    public String read(JsonReader in) throws IOException {\n      JsonToken peek = in.peek();\n      if (peek == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      /* coerce booleans to strings for backwards compatibility */\n      if (peek == JsonToken.BOOLEAN) {\n        return Boolean.toString(in.nextBoolean());\n      }\n      return in.nextString();\n    }\n    @Override\n    public void write(JsonWriter out, String value) throws IOException {\n      out.value(value);\n    }\n  };\n  \n  public static final TypeAdapter<BigDecimal> BIG_DECIMAL = new TypeAdapter<BigDecimal>() {\n    @Override\n    public BigDecimal read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      try {\n        return new BigDecimal(in.nextString());\n      } catch (NumberFormatException e) {\n        throw new JsonSyntaxException(e);\n      }\n    }\n\n    @Override\n    public void write(JsonWriter out, BigDecimal value) throws IOException {\n      out.value(value);\n    }\n  };\n  \n  public static final TypeAdapter<BigInteger> BIG_INTEGER = new TypeAdapter<BigInteger>() {\n    @Override\n    public BigInteger read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      try {\n        return new BigInteger(in.nextString());\n      } catch (NumberFormatException e) {\n        throw new JsonSyntaxException(e);\n      }\n    }\n\n    @Override\n    public void write(JsonWriter out, BigInteger value) throws IOException {\n      out.value(value);\n    }\n  };\n\n  public static final TypeAdapterFactory STRING_FACTORY = newFactory(String.class, STRING);\n\n  public static final TypeAdapter<StringBuilder> STRING_BUILDER = new TypeAdapter<StringBuilder>() {\n    @Override\n    public StringBuilder read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      return new StringBuilder(in.nextString());\n    }\n    @Override\n    public void write(JsonWriter out, StringBuilder value) throws IOException {\n      out.value(value == null ? null : value.toString());\n    }\n  };\n\n  public static final TypeAdapterFactory STRING_BUILDER_FACTORY =\n    newFactory(StringBuilder.class, STRING_BUILDER);\n\n  public static final TypeAdapter<StringBuffer> STRING_BUFFER = new TypeAdapter<StringBuffer>() {\n    @Override\n    public StringBuffer read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      return new StringBuffer(in.nextString());\n    }\n    @Override\n    public void write(JsonWriter out, StringBuffer value) throws IOException {\n      out.value(value == null ? null : value.toString());\n    }\n  };\n\n  public static final TypeAdapterFactory STRING_BUFFER_FACTORY =\n    newFactory(StringBuffer.class, STRING_BUFFER);\n\n  public static final TypeAdapter<java.net.URL> URL = new TypeAdapter<java.net.URL>() {\n    @Override\n    public java.net.URL read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      String nextString = in.nextString();\n      return \"null\".equals(nextString) ? null : new URL(nextString);\n    }\n    @Override\n    public void write(JsonWriter out, java.net.URL value) throws IOException {\n      out.value(value == null ? null : value.toExternalForm());\n    }\n  };\n\n  public static final TypeAdapterFactory URL_FACTORY = newFactory(java.net.URL.class, URL);\n\n  public static final TypeAdapter<java.net.URI> URI = new TypeAdapter<java.net.URI>() {\n    @Override\n    public java.net.URI read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      try {\n        String nextString = in.nextString();\n        return \"null\".equals(nextString) ? null : new URI(nextString);\n      } catch (URISyntaxException e) {\n        throw new JsonIOException(e);\n      }\n    }\n    @Override\n    public void write(JsonWriter out, java.net.URI value) throws IOException {\n      out.value(value == null ? null : value.toASCIIString());\n    }\n  };\n\n  public static final TypeAdapterFactory URI_FACTORY = newFactory(java.net.URI.class, URI);\n\n  public static final TypeAdapter<InetAddress> INET_ADDRESS = new TypeAdapter<InetAddress>() {\n    @Override\n    public InetAddress read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      // regrettably, this should have included both the host name and the host address\n      return InetAddress.getByName(in.nextString());\n    }\n    @Override\n    public void write(JsonWriter out, InetAddress value) throws IOException {\n      out.value(value == null ? null : value.getHostAddress());\n    }\n  };\n\n  public static final TypeAdapterFactory INET_ADDRESS_FACTORY =\n    newTypeHierarchyFactory(InetAddress.class, INET_ADDRESS);\n\n  public static final TypeAdapter<java.util.UUID> UUID = new TypeAdapter<java.util.UUID>() {\n    @Override\n    public java.util.UUID read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      return java.util.UUID.fromString(in.nextString());\n    }\n    @Override\n    public void write(JsonWriter out, java.util.UUID value) throws IOException {\n      out.value(value == null ? null : value.toString());\n    }\n  };\n\n  public static final TypeAdapterFactory UUID_FACTORY = newFactory(java.util.UUID.class, UUID);\n\n  public static final TypeAdapterFactory TIMESTAMP_FACTORY = new TypeAdapterFactory() {\n    @SuppressWarnings(\"unchecked\") // we use a runtime check to make sure the 'T's equal\n    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n      if (typeToken.getRawType() != Timestamp.class) {\n        return null;\n      }\n\n      final TypeAdapter<Date> dateTypeAdapter = gson.getAdapter(Date.class);\n      return (TypeAdapter<T>) new TypeAdapter<Timestamp>() {\n        @Override\n        public Timestamp read(JsonReader in) throws IOException {\n          Date date = dateTypeAdapter.read(in);\n          return date != null ? new Timestamp(date.getTime()) : null;\n        }\n\n        @Override\n        public void write(JsonWriter out, Timestamp value) throws IOException {\n          dateTypeAdapter.write(out, value);\n        }\n      };\n    }\n  };\n\n  public static final TypeAdapter<Calendar> CALENDAR = new TypeAdapter<Calendar>() {\n    private static final String YEAR = \"year\";\n    private static final String MONTH = \"month\";\n    private static final String DAY_OF_MONTH = \"dayOfMonth\";\n    private static final String HOUR_OF_DAY = \"hourOfDay\";\n    private static final String MINUTE = \"minute\";\n    private static final String SECOND = \"second\";\n\n    @Override\n    public Calendar read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return  null;\n      }\n      in.beginObject();\n      int year = 0;\n      int month = 0;\n      int dayOfMonth = 0;\n      int hourOfDay = 0;\n      int minute = 0;\n      int second = 0;\n      while (in.peek() != JsonToken.END_OBJECT) {\n        String name = in.nextName();\n        int value = in.nextInt();\n        if (YEAR.equals(name)) {\n          year = value;\n        } else if (MONTH.equals(name)) {\n          month = value;\n        } else if (DAY_OF_MONTH.equals(name)) {\n          dayOfMonth = value;\n        } else if (HOUR_OF_DAY.equals(name)) {\n          hourOfDay = value;\n        } else if (MINUTE.equals(name)) {\n          minute = value;\n        } else if (SECOND.equals(name)) {\n          second = value;\n        }\n      }\n      in.endObject();\n      return new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute, second);\n    }\n\n    @Override\n    public void write(JsonWriter out, Calendar value) throws IOException {\n      if (value == null) {\n        out.nullValue();\n        return;\n      }\n      out.beginObject();\n      out.name(YEAR);\n      out.value(value.get(Calendar.YEAR));\n      out.name(MONTH);\n      out.value(value.get(Calendar.MONTH));\n      out.name(DAY_OF_MONTH);\n      out.value(value.get(Calendar.DAY_OF_MONTH));\n      out.name(HOUR_OF_DAY);\n      out.value(value.get(Calendar.HOUR_OF_DAY));\n      out.name(MINUTE);\n      out.value(value.get(Calendar.MINUTE));\n      out.name(SECOND);\n      out.value(value.get(Calendar.SECOND));\n      out.endObject();\n    }\n  };\n\n  public static final TypeAdapterFactory CALENDAR_FACTORY =\n    newFactoryForMultipleTypes(Calendar.class, GregorianCalendar.class, CALENDAR);\n\n  public static final TypeAdapter<Locale> LOCALE = new TypeAdapter<Locale>() {\n    @Override\n    public Locale read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      String locale = in.nextString();\n      StringTokenizer tokenizer = new StringTokenizer(locale, \"_\");\n      String language = null;\n      String country = null;\n      String variant = null;\n      if (tokenizer.hasMoreElements()) {\n        language = tokenizer.nextToken();\n      }\n      if (tokenizer.hasMoreElements()) {\n        country = tokenizer.nextToken();\n      }\n      if (tokenizer.hasMoreElements()) {\n        variant = tokenizer.nextToken();\n      }\n      if (country == null && variant == null) {\n        return new Locale(language);\n      } else if (variant == null) {\n        return new Locale(language, country);\n      } else {\n        return new Locale(language, country, variant);\n      }\n    }\n    @Override\n    public void write(JsonWriter out, Locale value) throws IOException {\n      out.value(value == null ? null : value.toString());\n    }\n  };\n\n  public static final TypeAdapterFactory LOCALE_FACTORY = newFactory(Locale.class, LOCALE);\n\n  public static final TypeAdapter<JsonElement> JSON_ELEMENT = new TypeAdapter<JsonElement>() {\n    @Override\n    public JsonElement read(JsonReader in) throws IOException {\n      switch (in.peek()) {\n      case STRING:\n        return new JsonPrimitive(in.nextString());\n      case NUMBER:\n        String number = in.nextString();\n        return new JsonPrimitive(new LazilyParsedNumber(number));\n      case BOOLEAN:\n        return new JsonPrimitive(in.nextBoolean());\n      case NULL:\n        in.nextNull();\n        return JsonNull.INSTANCE;\n      case BEGIN_ARRAY:\n        JsonArray array = new JsonArray();\n        in.beginArray();\n        while (in.hasNext()) {\n          array.add(read(in));\n        }\n        in.endArray();\n        return array;\n      case BEGIN_OBJECT:\n        JsonObject object = new JsonObject();\n        in.beginObject();\n        while (in.hasNext()) {\n          object.add(in.nextName(), read(in));\n        }\n        in.endObject();\n        return object;\n      case END_DOCUMENT:\n      case NAME:\n      case END_OBJECT:\n      case END_ARRAY:\n      default:\n        throw new IllegalArgumentException();\n      }\n    }\n\n    @Override\n    public void write(JsonWriter out, JsonElement value) throws IOException {\n      if (value == null || value.isJsonNull()) {\n        out.nullValue();\n      } else if (value.isJsonPrimitive()) {\n        JsonPrimitive primitive = value.getAsJsonPrimitive();\n        if (primitive.isNumber()) {\n          out.value(primitive.getAsNumber());\n        } else if (primitive.isBoolean()) {\n          out.value(primitive.getAsBoolean());\n        } else {\n          out.value(primitive.getAsString());\n        }\n\n      } else if (value.isJsonArray()) {\n        out.beginArray();\n        for (JsonElement e : value.getAsJsonArray()) {\n          write(out, e);\n        }\n        out.endArray();\n\n      } else if (value.isJsonObject()) {\n        out.beginObject();\n        for (Map.Entry<String, JsonElement> e : value.getAsJsonObject().entrySet()) {\n          out.name(e.getKey());\n          write(out, e.getValue());\n        }\n        out.endObject();\n\n      } else {\n        throw new IllegalArgumentException(\"Couldn't write \" + value.getClass());\n      }\n    }\n  };\n\n  public static final TypeAdapterFactory JSON_ELEMENT_FACTORY\n      = newFactory(JsonElement.class, JSON_ELEMENT);\n\n  private static final class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {\n    private final Map<String, T> nameToConstant = new HashMap<String, T>();\n    private final Map<T, String> constantToName = new HashMap<T, String>();\n\n    public EnumTypeAdapter(Class<T> classOfT) {\n      try {\n        for (T constant : classOfT.getEnumConstants()) {\n          String name = constant.name();\n          SerializedName annotation = classOfT.getField(name).getAnnotation(SerializedName.class);\n          if (annotation != null) {\n            name = annotation.value();\n          }\n          nameToConstant.put(name, constant);\n          constantToName.put(constant, name);\n        }\n      } catch (NoSuchFieldException e) {\n        throw new AssertionError();\n      }\n    }\n    public T read(JsonReader in) throws IOException {\n      if (in.peek() == JsonToken.NULL) {\n        in.nextNull();\n        return null;\n      }\n      return nameToConstant.get(in.nextString());\n    }\n\n    public void write(JsonWriter out, T value) throws IOException {\n      out.value(value == null ? null : constantToName.get(value));\n    }\n  }\n\n  public static final TypeAdapterFactory ENUM_FACTORY = newEnumTypeHierarchyFactory();\n\n  public static TypeAdapterFactory newEnumTypeHierarchyFactory() {\n    return new TypeAdapterFactory() {\n      @SuppressWarnings({\"rawtypes\", \"unchecked\"})\n      public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n        Class<? super T> rawType = typeToken.getRawType();\n        if (!Enum.class.isAssignableFrom(rawType) || rawType == Enum.class) {\n          return null;\n        }\n        if (!rawType.isEnum()) {\n          rawType = rawType.getSuperclass(); // handle anonymous subclasses\n        }\n        return (TypeAdapter<T>) new EnumTypeAdapter(rawType);\n      }\n    };\n  }\n\n  public static <TT> TypeAdapterFactory newFactory(\n      final TypeToken<TT> type, final TypeAdapter<TT> typeAdapter) {\n    return new TypeAdapterFactory() {\n      @SuppressWarnings(\"unchecked\") // we use a runtime check to make sure the 'T's equal\n      public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n        return typeToken.equals(type) ? (TypeAdapter<T>) typeAdapter : null;\n      }\n    };\n  }\n\n  public static <TT> TypeAdapterFactory newFactory(\n          final Class<TT> type, final TypeAdapter<TT> typeAdapter) {\n    return new TypeAdapterFactory() {\n      @SuppressWarnings(\"unchecked\") // we use a runtime check to make sure the 'T's equal\n      public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n        return typeToken.getRawType() == type ? (TypeAdapter<T>) typeAdapter : null;\n      }\n      @Override\n      public String toString() {\n        return \"Factory[type=\" + type.getName() + \",adapter=\" + typeAdapter + \"]\";\n      }\n    };\n  }\n\n  public static <TT> TypeAdapterFactory newFactory(\n          final Class<TT> unboxed, final Class<TT> boxed, final TypeAdapter<? super TT> typeAdapter) {\n    return new TypeAdapterFactory() {\n      @SuppressWarnings(\"unchecked\") // we use a runtime check to make sure the 'T's equal\n      public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n        Class<? super T> rawType = typeToken.getRawType();\n        return (rawType == unboxed || rawType == boxed) ? (TypeAdapter<T>) typeAdapter : null;\n      }\n      @Override\n      public String toString() {\n        return \"Factory[type=\" + boxed.getName()\n            + \"+\" + unboxed.getName() + \",adapter=\" + typeAdapter + \"]\";\n      }\n    };\n  }\n\n  public static <TT> TypeAdapterFactory newFactoryForMultipleTypes(final Class<TT> base,\n                                                                   final Class<? extends TT> sub, final TypeAdapter<? super TT> typeAdapter) {\n    return new TypeAdapterFactory() {\n      @SuppressWarnings(\"unchecked\") // we use a runtime check to make sure the 'T's equal\n      public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n        Class<? super T> rawType = typeToken.getRawType();\n        return (rawType == base || rawType == sub) ? (TypeAdapter<T>) typeAdapter : null;\n      }\n      @Override\n      public String toString() {\n        return \"Factory[type=\" + base.getName()\n            + \"+\" + sub.getName() + \",adapter=\" + typeAdapter + \"]\";\n      }\n    };\n  }\n\n  public static <TT> TypeAdapterFactory newTypeHierarchyFactory(\n          final Class<TT> clazz, final TypeAdapter<TT> typeAdapter) {\n    return new TypeAdapterFactory() {\n      @SuppressWarnings(\"unchecked\")\n      public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {\n        return clazz.isAssignableFrom(typeToken.getRawType()) ? (TypeAdapter<T>) typeAdapter : null;\n      }\n      @Override\n      public String toString() {\n        return \"Factory[typeHierarchy=\" + clazz.getName() + \",adapter=\" + typeAdapter + \"]\";\n      }\n    };\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/internal/package-info.java",
    "content": "/**\n * Do NOT use any class in this package as they are meant for internal use in Gson.\n * These classes will very likely change incompatibly in future versions. You have been warned.\n *\n * @author Inderjeet Singh, Joel Leitch, Jesse Wilson\n */\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.internal;"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/package-info.java",
    "content": "/**\n * This package provides the {@link com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson} class to convert Json to Java and\n * vice-versa.\n *\n * <p>The primary class to use is {@link com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson} which can be constructed with\n * {@code new Gson()} (using default settings) or by using {@link com.bzai.gamesdk.common.utils_base.frame.google.gson.GsonBuilder}\n * (to configure various options such as using versioning and so on).</p>\n *\n * @author Inderjeet Singh, Joel Leitch\n */\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson;"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/reflect/TypeToken.java",
    "content": "/*\n * Copyright (C) 2008 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.$Gson$Preconditions;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.$Gson$Types;\n\nimport java.lang.reflect.GenericArrayType;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Represents a generic type {@code T}. Java doesn't yet provide a way to\n * represent generic types, so this class does. Forces clients to create a\n * subclass of this class which enables retrieval the type information even at\n * runtime.\n *\n * <p>For example, to create a type literal for {@code List<String>}, you can\n * create an empty anonymous inner class:\n *\n * <p>\n * {@code TypeToken<List<String>> list = new TypeToken<List<String>>() {};}\n *\n * <p>This syntax cannot be used to create type literals that have wildcard\n * parameters, such as {@code Class<?>} or {@code List<? extends CharSequence>}.\n *\n * @author Bob Lee\n * @author Sven Mawson\n * @author Jesse Wilson\n */\npublic class TypeToken<T> {\n  final Class<? super T> rawType;\n  final Type type;\n  final int hashCode;\n\n  /**\n   * Constructs a new type literal. Derives represented class from type\n   * parameter.\n   *\n   * <p>Clients create an empty anonymous subclass. Doing so embeds the type\n   * parameter in the anonymous class's type hierarchy so we can reconstitute it\n   * at runtime despite erasure.\n   */\n  @SuppressWarnings(\"unchecked\")\n  protected TypeToken() {\n    this.type = getSuperclassTypeParameter(getClass());\n    this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);\n    this.hashCode = type.hashCode();\n  }\n\n  /**\n   * Unsafe. Constructs a type literal manually.\n   */\n  @SuppressWarnings(\"unchecked\")\n  TypeToken(Type type) {\n    this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type));\n    this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type);\n    this.hashCode = this.type.hashCode();\n  }\n\n  /**\n   * Returns the type from super class's type parameter in {@link $Gson$Types#canonicalize\n   * canonical form}.\n   */\n  static Type getSuperclassTypeParameter(Class<?> subclass) {\n    Type superclass = subclass.getGenericSuperclass();\n    if (superclass instanceof Class) {\n      throw new RuntimeException(\"Missing type parameter.\");\n    }\n    ParameterizedType parameterized = (ParameterizedType) superclass;\n    return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);\n  }\n\n  /**\n   * Returns the raw (non-generic) type for this type.\n   */\n  public final Class<? super T> getRawType() {\n    return rawType;\n  }\n\n  /**\n   * Gets underlying {@code Type} instance.\n   */\n  public final Type getType() {\n    return type;\n  }\n\n  /**\n   * Check if this type is assignable from the given class object.\n   *\n   * @deprecated this implementation may be inconsistent with javac for types\n   *     with wildcards.\n   */\n  @Deprecated\n  public boolean isAssignableFrom(Class<?> cls) {\n    return isAssignableFrom((Type) cls);\n  }\n\n  /**\n   * Check if this type is assignable from the given Type.\n   *\n   * @deprecated this implementation may be inconsistent with javac for types\n   *     with wildcards.\n   */\n  @Deprecated\n  public boolean isAssignableFrom(Type from) {\n    if (from == null) {\n      return false;\n    }\n\n    if (type.equals(from)) {\n      return true;\n    }\n\n    if (type instanceof Class<?>) {\n      return rawType.isAssignableFrom($Gson$Types.getRawType(from));\n    } else if (type instanceof ParameterizedType) {\n      return isAssignableFrom(from, (ParameterizedType) type,\n          new HashMap<String, Type>());\n    } else if (type instanceof GenericArrayType) {\n      return rawType.isAssignableFrom($Gson$Types.getRawType(from))\n          && isAssignableFrom(from, (GenericArrayType) type);\n    } else {\n      throw buildUnexpectedTypeError(\n          type, Class.class, ParameterizedType.class, GenericArrayType.class);\n    }\n  }\n\n  /**\n   * Check if this type is assignable from the given type token.\n   *\n   * @deprecated this implementation may be inconsistent with javac for types\n   *     with wildcards.\n   */\n  @Deprecated\n  public boolean isAssignableFrom(TypeToken<?> token) {\n    return isAssignableFrom(token.getType());\n  }\n\n  /**\n   * Private helper function that performs some assignability checks for\n   * the provided GenericArrayType.\n   */\n  private static boolean isAssignableFrom(Type from, GenericArrayType to) {\n    Type toGenericComponentType = to.getGenericComponentType();\n    if (toGenericComponentType instanceof ParameterizedType) {\n      Type t = from;\n      if (from instanceof GenericArrayType) {\n        t = ((GenericArrayType) from).getGenericComponentType();\n      } else if (from instanceof Class<?>) {\n        Class<?> classType = (Class<?>) from;\n        while (classType.isArray()) {\n          classType = classType.getComponentType();\n        }\n        t = classType;\n      }\n      return isAssignableFrom(t, (ParameterizedType) toGenericComponentType,\n          new HashMap<String, Type>());\n    }\n    // No generic defined on \"to\"; therefore, return true and let other\n    // checks determine assignability\n    return true;\n  }\n\n  /**\n   * Private recursive helper function to actually do the type-safe checking\n   * of assignability.\n   */\n  private static boolean isAssignableFrom(Type from, ParameterizedType to,\n                                          Map<String, Type> typeVarMap) {\n\n    if (from == null) {\n      return false;\n    }\n\n    if (to.equals(from)) {\n      return true;\n    }\n\n    // First figure out the class and any type information.\n    Class<?> clazz = $Gson$Types.getRawType(from);\n    ParameterizedType ptype = null;\n    if (from instanceof ParameterizedType) {\n      ptype = (ParameterizedType) from;\n    }\n\n    // Load up parameterized variable info if it was parameterized.\n    if (ptype != null) {\n      Type[] tArgs = ptype.getActualTypeArguments();\n      TypeVariable<?>[] tParams = clazz.getTypeParameters();\n      for (int i = 0; i < tArgs.length; i++) {\n        Type arg = tArgs[i];\n        TypeVariable<?> var = tParams[i];\n        while (arg instanceof TypeVariable<?>) {\n          TypeVariable<?> v = (TypeVariable<?>) arg;\n          arg = typeVarMap.get(v.getName());\n        }\n        typeVarMap.put(var.getName(), arg);\n      }\n\n      // check if they are equivalent under our current mapping.\n      if (typeEquals(ptype, to, typeVarMap)) {\n        return true;\n      }\n    }\n\n    for (Type itype : clazz.getGenericInterfaces()) {\n      if (isAssignableFrom(itype, to, new HashMap<String, Type>(typeVarMap))) {\n        return true;\n      }\n    }\n\n    // Interfaces didn't work, try the superclass.\n    Type sType = clazz.getGenericSuperclass();\n    return isAssignableFrom(sType, to, new HashMap<String, Type>(typeVarMap));\n  }\n\n  /**\n   * Checks if two parameterized types are exactly equal, under the variable\n   * replacement described in the typeVarMap.\n   */\n  private static boolean typeEquals(ParameterizedType from,\n                                    ParameterizedType to, Map<String, Type> typeVarMap) {\n    if (from.getRawType().equals(to.getRawType())) {\n      Type[] fromArgs = from.getActualTypeArguments();\n      Type[] toArgs = to.getActualTypeArguments();\n      for (int i = 0; i < fromArgs.length; i++) {\n        if (!matches(fromArgs[i], toArgs[i], typeVarMap)) {\n          return false;\n        }\n      }\n      return true;\n    }\n    return false;\n  }\n\n  private static AssertionError buildUnexpectedTypeError(\n          Type token, Class<?>... expected) {\n\n    // Build exception message\n    StringBuilder exceptionMessage =\n        new StringBuilder(\"Unexpected type. Expected one of: \");\n    for (Class<?> clazz : expected) {\n      exceptionMessage.append(clazz.getName()).append(\", \");\n    }\n    exceptionMessage.append(\"but got: \").append(token.getClass().getName())\n        .append(\", for type token: \").append(token.toString()).append('.');\n\n    return new AssertionError(exceptionMessage.toString());\n  }\n\n  /**\n   * Checks if two types are the same or are equivalent under a variable mapping\n   * given in the type map that was provided.\n   */\n  private static boolean matches(Type from, Type to, Map<String, Type> typeMap) {\n    return to.equals(from)\n        || (from instanceof TypeVariable\n        && to.equals(typeMap.get(((TypeVariable<?>) from).getName())));\n\n  }\n\n  @Override\n  public final int hashCode() {\n    return this.hashCode;\n  }\n\n  @Override\n  public final boolean equals(Object o) {\n    return o instanceof TypeToken<?>\n        && $Gson$Types.equals(type, ((TypeToken<?>) o).type);\n  }\n\n  @Override\n  public final String toString() {\n    return $Gson$Types.typeToString(type);\n  }\n\n  /**\n   * Gets type literal for the given {@code Type} instance.\n   */\n  public static TypeToken<?> get(Type type) {\n    return new TypeToken<Object>(type);\n  }\n\n  /**\n   * Gets type literal for the given {@code Class} instance.\n   */\n  public static <T> TypeToken<T> get(Class<T> type) {\n    return new TypeToken<T>(type);\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/reflect/package-info.java",
    "content": "/**\n * This package provides utility classes for finding type information for generic types.\n *  \n * @author Inderjeet Singh, Joel Leitch\n */\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.reflect;"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/stream/JsonReader.java",
    "content": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.stream;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.JsonReaderInternalAccess;\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.internal.bind.JsonTreeReader;\n\nimport java.io.Closeable;\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.Reader;\n\n/**\n * Reads a JSON (<a href=\"http://www.ietf.org/rfc/rfc4627.txt\">RFC 4627</a>)\n * encoded value as a stream of tokens. This stream includes both literal\n * values (strings, numbers, booleans, and nulls) as well as the begin and\n * end delimiters of objects and arrays. The tokens are traversed in\n * depth-first order, the same order that they appear in the JSON document.\n * Within JSON objects, name/value pairs are represented by a single token.\n *\n * <h3>Parsing JSON</h3>\n * To create a recursive descent parser for your own JSON streams, first create\n * an entry point method that creates a {@code JsonReader}.\n *\n * <p>Next, create handler methods for each structure in your JSON text. You'll\n * need a method for each object type and for each array type.\n * <ul>\n *   <li>Within <strong>array handling</strong> methods, first call {@link\n *       #beginArray} to consume the array's opening bracket. Then create a\n *       while loop that accumulates values, terminating when {@link #hasNext}\n *       is false. Finally, read the array's closing bracket by calling {@link\n *       #endArray}.\n *   <li>Within <strong>object handling</strong> methods, first call {@link\n *       #beginObject} to consume the object's opening brace. Then create a\n *       while loop that assigns values to local variables based on their name.\n *       This loop should terminate when {@link #hasNext} is false. Finally,\n *       read the object's closing brace by calling {@link #endObject}.\n * </ul>\n * <p>When a nested object or array is encountered, delegate to the\n * corresponding handler method.\n *\n * <p>When an unknown name is encountered, strict parsers should fail with an\n * exception. Lenient parsers should call {@link #skipValue()} to recursively\n * skip the value's nested tokens, which may otherwise conflict.\n *\n * <p>If a value may be null, you should first check using {@link #peek()}.\n * Null literals can be consumed using either {@link #nextNull()} or {@link\n * #skipValue()}.\n *\n * <h3>Example</h3>\n * Suppose we'd like to parse a stream of messages such as the following: <pre> {@code\n * [\n *   {\n *     \"id\": 912345678901,\n *     \"text\": \"How do I read a JSON stream in Java?\",\n *     \"geo\": null,\n *     \"user\": {\n *       \"name\": \"json_newb\",\n *       \"followers_count\": 41\n *      }\n *   },\n *   {\n *     \"id\": 912345678902,\n *     \"text\": \"@json_newb just use JsonReader!\",\n *     \"geo\": [50.454722, -104.606667],\n *     \"user\": {\n *       \"name\": \"jesse\",\n *       \"followers_count\": 2\n *     }\n *   }\n * ]}</pre>\n * This code implements the parser for the above structure: <pre>   {@code\n *\n *   public List<Message> readJsonStream(InputStream in) throws IOException {\n *     JsonReader reader = new JsonReader(new InputStreamReader(in, \"UTF-8\"));\n *     try {\n *       return readMessagesArray(reader);\n *     } finally {\n *       reader.close();\n *     }\n *   }\n *\n *   public List<Message> readMessagesArray(JsonReader reader) throws IOException {\n *     List<Message> messages = new ArrayList<Message>();\n *\n *     reader.beginArray();\n *     while (reader.hasNext()) {\n *       messages.add(readMessage(reader));\n *     }\n *     reader.endArray();\n *     return messages;\n *   }\n *\n *   public Message readMessage(JsonReader reader) throws IOException {\n *     long id = -1;\n *     String text = null;\n *     User user = null;\n *     List<Double> geo = null;\n *\n *     reader.beginObject();\n *     while (reader.hasNext()) {\n *       String name = reader.nextName();\n *       if (name.equals(\"id\")) {\n *         id = reader.nextLong();\n *       } else if (name.equals(\"text\")) {\n *         text = reader.nextString();\n *       } else if (name.equals(\"geo\") && reader.peek() != JsonToken.NULL) {\n *         geo = readDoublesArray(reader);\n *       } else if (name.equals(\"user\")) {\n *         user = readUser(reader);\n *       } else {\n *         reader.skipValue();\n *       }\n *     }\n *     reader.endObject();\n *     return new Message(id, text, user, geo);\n *   }\n *\n *   public List<Double> readDoublesArray(JsonReader reader) throws IOException {\n *     List<Double> doubles = new ArrayList<Double>();\n *\n *     reader.beginArray();\n *     while (reader.hasNext()) {\n *       doubles.add(reader.nextDouble());\n *     }\n *     reader.endArray();\n *     return doubles;\n *   }\n *\n *   public User readUser(JsonReader reader) throws IOException {\n *     String username = null;\n *     int followersCount = -1;\n *\n *     reader.beginObject();\n *     while (reader.hasNext()) {\n *       String name = reader.nextName();\n *       if (name.equals(\"name\")) {\n *         username = reader.nextString();\n *       } else if (name.equals(\"followers_count\")) {\n *         followersCount = reader.nextInt();\n *       } else {\n *         reader.skipValue();\n *       }\n *     }\n *     reader.endObject();\n *     return new User(username, followersCount);\n *   }}</pre>\n *\n * <h3>Number Handling</h3>\n * This reader permits numeric values to be read as strings and string values to\n * be read as numbers. For example, both elements of the JSON array {@code\n * [1, \"1\"]} may be read using either {@link #nextInt} or {@link #nextString}.\n * This behavior is intended to prevent lossy numeric conversions: double is\n * JavaScript's only numeric type and very large values like {@code\n * 9007199254740993} cannot be represented exactly on that platform. To minimize\n * precision loss, extremely large values should be written and read as strings\n * in JSON.\n *\n * <a name=\"nonexecuteprefix\"/><h3>Non-Execute Prefix</h3>\n * Web servers that serve private data using JSON may be vulnerable to <a\n * href=\"http://en.wikipedia.org/wiki/JSON#Cross-site_request_forgery\">Cross-site\n * request forgery</a> attacks. In such an attack, a malicious site gains access\n * to a private JSON file by executing it with an HTML {@code <script>} tag.\n *\n * <p>Prefixing JSON files with <code>\")]}'\\n\"</code> makes them non-executable\n * by {@code <script>} tags, disarming the attack. Since the prefix is malformed\n * JSON, strict parsing fails when it is encountered. This class permits the\n * non-execute prefix when {@link #setLenient(boolean) lenient parsing} is\n * enabled.\n *\n * <p>Each {@code JsonReader} may be used to read a single JSON stream. Instances\n * of this class are not thread safe.\n *\n * @author Jesse Wilson\n * @since 1.6\n */\npublic class JsonReader implements Closeable {\n\n  /** The only non-execute prefix this parser permits */\n  private static final char[] NON_EXECUTE_PREFIX = \")]}'\\n\".toCharArray();\n\n  private static final String TRUE = \"true\";\n  private static final String FALSE = \"false\";\n\n  private final StringPool stringPool = new StringPool();\n\n  /** The input JSON. */\n  private final Reader in;\n\n  /** True to accept non-spec compliant JSON */\n  private boolean lenient = false;\n\n  /**\n   * Use a manual buffer to easily read and unread upcoming characters, and\n   * also so we can create strings without an intermediate StringBuilder.\n   * We decode literals directly out of this buffer, so it must be at least as\n   * long as the longest token that can be reported as a number.\n   */\n  private final char[] buffer = new char[1024];\n  private int pos = 0;\n  private int limit = 0;\n\n  /*\n   * The offset of the first character in the buffer.\n   */\n  private int bufferStartLine = 1;\n  private int bufferStartColumn = 1;\n\n  /*\n   * The nesting stack. Using a manual array rather than an ArrayList saves 20%.\n   */\n  private JsonScope[] stack = new JsonScope[32];\n  private int stackSize = 0;\n  {\n    push(JsonScope.EMPTY_DOCUMENT);\n  }\n\n  /**\n   * The type of the next token to be returned by {@link #peek} and {@link\n   * #advance}. If null, peek() will assign a value.\n   */\n  private JsonToken token;\n\n  /** The text of the next name. */\n  private String name;\n\n  /*\n   * For the next literal value, we may have the text value, or the position\n   * and length in the buffer.\n   */\n  private String value;\n  private int valuePos;\n  private int valueLength;\n\n  /** True if we're currently handling a skipValue() call. */\n  private boolean skipping = false;\n\n  /**\n   * Creates a new instance that reads a JSON-encoded stream from {@code in}.\n   */\n  public JsonReader(Reader in) {\n    if (in == null) {\n      throw new NullPointerException(\"in == null\");\n    }\n    this.in = in;\n  }\n\n  /**\n   * Configure this parser to be  be liberal in what it accepts. By default,\n   * this parser is strict and only accepts JSON as specified by <a\n   * href=\"http://www.ietf.org/rfc/rfc4627.txt\">RFC 4627</a>. Setting the\n   * parser to lenient causes it to ignore the following syntax errors:\n   *\n   * <ul>\n   *   <li>Streams that start with the <a href=\"#nonexecuteprefix\">non-execute\n   *       prefix</a>, <code>\")]}'\\n\"</code>.\n   *   <li>Streams that include multiple top-level values. With strict parsing,\n   *       each stream must contain exactly one top-level value.\n   *   <li>Top-level values of any type. With strict parsing, the top-level\n   *       value must be an object or an array.\n   *   <li>Numbers may be {@link Double#isNaN() NaNs} or {@link\n   *       Double#isInfinite() infinities}.\n   *   <li>End of line comments starting with {@code //} or {@code #} and\n   *       ending with a newline character.\n   *   <li>C-style comments starting with {@code /*} and ending with\n   *       {@code *}{@code /}. Such comments may not be nested.\n   *   <li>Names that are unquoted or {@code 'single quoted'}.\n   *   <li>Strings that are unquoted or {@code 'single quoted'}.\n   *   <li>Array elements separated by {@code ;} instead of {@code ,}.\n   *   <li>Unnecessary array separators. These are interpreted as if null\n   *       was the omitted value.\n   *   <li>Names and values separated by {@code =} or {@code =>} instead of\n   *       {@code :}.\n   *   <li>Name/value pairs separated by {@code ;} instead of {@code ,}.\n   * </ul>\n   */\n  public final void setLenient(boolean lenient) {\n    this.lenient = lenient;\n  }\n\n  /**\n   * Returns true if this parser is liberal in what it accepts.\n   */\n  public final boolean isLenient() {\n    return lenient;\n  }\n\n  /**\n   * Consumes the next token from the JSON stream and asserts that it is the\n   * beginning of a new array.\n   */\n  public void beginArray() throws IOException {\n    expect(JsonToken.BEGIN_ARRAY);\n  }\n\n  /**\n   * Consumes the next token from the JSON stream and asserts that it is the\n   * end of the current array.\n   */\n  public void endArray() throws IOException {\n    expect(JsonToken.END_ARRAY);\n  }\n\n  /**\n   * Consumes the next token from the JSON stream and asserts that it is the\n   * beginning of a new object.\n   */\n  public void beginObject() throws IOException {\n    expect(JsonToken.BEGIN_OBJECT);\n  }\n\n  /**\n   * Consumes the next token from the JSON stream and asserts that it is the\n   * end of the current object.\n   */\n  public void endObject() throws IOException {\n    expect(JsonToken.END_OBJECT);\n  }\n\n  /**\n   * Consumes {@code expected}.\n   */\n  private void expect(JsonToken expected) throws IOException {\n    peek();\n    if (token != expected) {\n      throw new IllegalStateException(\"Expected \" + expected + \" but was \" + peek()\n          + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    }\n    advance();\n  }\n\n  /**\n   * Returns true if the current array or object has another element.\n   */\n  public boolean hasNext() throws IOException {\n    peek();\n    return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY;\n  }\n\n  /**\n   * Returns the type of the next token without consuming it.\n   */\n  public JsonToken peek() throws IOException {\n    if (token != null) {\n      return token;\n    }\n\n    switch (stack[stackSize - 1]) {\n    case EMPTY_DOCUMENT:\n      if (lenient) {\n        consumeNonExecutePrefix();\n      }\n      stack[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT;\n      JsonToken firstToken = nextValue();\n      if (!lenient && token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) {\n        throw new IOException(\"Expected JSON document to start with '[' or '{' but was \" + token\n            + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n      }\n      return firstToken;\n    case EMPTY_ARRAY:\n      return nextInArray(true);\n    case NONEMPTY_ARRAY:\n      return nextInArray(false);\n    case EMPTY_OBJECT:\n      return nextInObject(true);\n    case DANGLING_NAME:\n      return objectValue();\n    case NONEMPTY_OBJECT:\n      return nextInObject(false);\n    case NONEMPTY_DOCUMENT:\n      int c = nextNonWhitespace(false);\n      if (c == -1) {\n        return JsonToken.END_DOCUMENT;\n      }\n      pos--;\n      if (!lenient) {\n        throw syntaxError(\"Expected EOF\");\n      }\n      return nextValue();\n    case CLOSED:\n      throw new IllegalStateException(\"JsonReader is closed\");\n    default:\n      throw new AssertionError();\n    }\n  }\n\n  /**\n   * Consumes the non-execute prefix if it exists.\n   */\n  private void consumeNonExecutePrefix() throws IOException {\n    // fast forward through the leading whitespace\n    nextNonWhitespace(true);\n    pos--;\n\n    if (pos + NON_EXECUTE_PREFIX.length > limit && !fillBuffer(NON_EXECUTE_PREFIX.length)) {\n      return;\n    }\n\n    for (int i = 0; i < NON_EXECUTE_PREFIX.length; i++) {\n      if (buffer[pos + i] != NON_EXECUTE_PREFIX[i]) {\n        return; // not a security token!\n      }\n    }\n\n    // we consumed a security token!\n    pos += NON_EXECUTE_PREFIX.length;\n  }\n\n  /**\n   * Advances the cursor in the JSON stream to the next token.\n   */\n  private JsonToken advance() throws IOException {\n    peek();\n\n    JsonToken result = token;\n    token = null;\n    value = null;\n    name = null;\n    return result;\n  }\n\n  /**\n   * Returns the next token, a {@link JsonToken#NAME property name}, and\n   * consumes it.\n   *\n   * @throws IOException if the next token in the stream is not a property\n   *     name.\n   */\n  public String nextName() throws IOException {\n    peek();\n    if (token != JsonToken.NAME) {\n      throw new IllegalStateException(\"Expected a name but was \" + peek()\n          + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    }\n    String result = name;\n    advance();\n    return result;\n  }\n\n  /**\n   * Returns the {@link JsonToken#STRING string} value of the next token,\n   * consuming it. If the next token is a number, this method will return its\n   * string form.\n   *\n   * @throws IllegalStateException if the next token is not a string or if\n   *     this reader is closed.\n   */\n  public String nextString() throws IOException {\n    peek();\n    if (token != JsonToken.STRING && token != JsonToken.NUMBER) {\n      throw new IllegalStateException(\"Expected a string but was \" + peek()\n          + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    }\n\n    String result = value;\n    advance();\n    return result;\n  }\n\n  /**\n   * Returns the {@link JsonToken#BOOLEAN boolean} value of the next token,\n   * consuming it.\n   *\n   * @throws IllegalStateException if the next token is not a boolean or if\n   *     this reader is closed.\n   */\n  public boolean nextBoolean() throws IOException {\n    peek();\n    if (token != JsonToken.BOOLEAN) {\n        throw new IllegalStateException(\"Expected a boolean but was \" + token\n            + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    }\n\n    boolean result = (value == TRUE);\n    advance();\n    return result;\n  }\n\n  /**\n   * Consumes the next token from the JSON stream and asserts that it is a\n   * literal null.\n   *\n   * @throws IllegalStateException if the next token is not null or if this\n   *     reader is closed.\n   */\n  public void nextNull() throws IOException {\n    peek();\n    if (token != JsonToken.NULL) {\n      throw new IllegalStateException(\"Expected null but was \" + token\n          + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    }\n\n    advance();\n  }\n\n  /**\n   * Returns the {@link JsonToken#NUMBER double} value of the next token,\n   * consuming it. If the next token is a string, this method will attempt to\n   * parse it as a double using {@link Double#parseDouble(String)}.\n   *\n   * @throws IllegalStateException if the next token is not a literal value.\n   * @throws NumberFormatException if the next literal value cannot be parsed\n   *     as a double, or is non-finite.\n   */\n  public double nextDouble() throws IOException {\n    peek();\n    if (token != JsonToken.STRING && token != JsonToken.NUMBER) {\n      throw new IllegalStateException(\"Expected a double but was \" + token\n          + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    }\n\n    double result = Double.parseDouble(value);\n\n    if ((result >= 1.0d && value.startsWith(\"0\"))) {\n      throw new MalformedJsonException(\"JSON forbids octal prefixes: \" + value\n          + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    }\n    if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) {\n      throw new MalformedJsonException(\"JSON forbids NaN and infinities: \" + value\n          + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    }\n\n    advance();\n    return result;\n  }\n\n  /**\n   * Returns the {@link JsonToken#NUMBER long} value of the next token,\n   * consuming it. If the next token is a string, this method will attempt to\n   * parse it as a long. If the next token's numeric value cannot be exactly\n   * represented by a Java {@code long}, this method throws.\n   *\n   * @throws IllegalStateException if the next token is not a literal value.\n   * @throws NumberFormatException if the next literal value cannot be parsed\n   *     as a number, or exactly represented as a long.\n   */\n  public long nextLong() throws IOException {\n    peek();\n    if (token != JsonToken.STRING && token != JsonToken.NUMBER) {\n      throw new IllegalStateException(\"Expected a long but was \" + token\n          + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    }\n\n    long result;\n    try {\n      result = Long.parseLong(value);\n    } catch (NumberFormatException ignored) {\n      double asDouble = Double.parseDouble(value); // don't catch this NumberFormatException\n      result = (long) asDouble;\n      if (result != asDouble) {\n        throw new NumberFormatException(\"Expected a long but was \" + value\n            + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n      }\n    }\n\n    if (result >= 1L && value.startsWith(\"0\")) {\n      throw new MalformedJsonException(\"JSON forbids octal prefixes: \" + value\n          + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    }\n\n    advance();\n    return result;\n  }\n\n  /**\n   * Returns the {@link JsonToken#NUMBER int} value of the next token,\n   * consuming it. If the next token is a string, this method will attempt to\n   * parse it as an int. If the next token's numeric value cannot be exactly\n   * represented by a Java {@code int}, this method throws.\n   *\n   * @throws IllegalStateException if the next token is not a literal value.\n   * @throws NumberFormatException if the next literal value cannot be parsed\n   *     as a number, or exactly represented as an int.\n   */\n  public int nextInt() throws IOException {\n    peek();\n    if (token != JsonToken.STRING && token != JsonToken.NUMBER) {\n      throw new IllegalStateException(\"Expected an int but was \" + token\n          + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    }\n\n    int result;\n    try {\n      result = Integer.parseInt(value);\n    } catch (NumberFormatException ignored) {\n      double asDouble = Double.parseDouble(value); // don't catch this NumberFormatException\n      result = (int) asDouble;\n      if (result != asDouble) {\n        throw new NumberFormatException(\"Expected an int but was \" + value\n            + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n      }\n    }\n\n    if (result >= 1L && value.startsWith(\"0\")) {\n      throw new MalformedJsonException(\"JSON forbids octal prefixes: \" + value\n          + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    }\n\n    advance();\n    return result;\n  }\n\n  /**\n   * Closes this JSON reader and the underlying {@link Reader}.\n   */\n  public void close() throws IOException {\n    value = null;\n    token = null;\n    stack[0] = JsonScope.CLOSED;\n    stackSize = 1;\n    in.close();\n  }\n\n  /**\n   * Skips the next value recursively. If it is an object or array, all nested\n   * elements are skipped. This method is intended for use when the JSON token\n   * stream contains unrecognized or unhandled values.\n   */\n  public void skipValue() throws IOException {\n    skipping = true;\n    try {\n      int count = 0;\n      do {\n        JsonToken token = advance();\n        if (token == JsonToken.BEGIN_ARRAY || token == JsonToken.BEGIN_OBJECT) {\n          count++;\n        } else if (token == JsonToken.END_ARRAY || token == JsonToken.END_OBJECT) {\n          count--;\n        }\n      } while (count != 0);\n    } finally {\n      skipping = false;\n    }\n  }\n\n  private void push(JsonScope newTop) {\n    if (stackSize == stack.length) {\n      JsonScope[] newStack = new JsonScope[stackSize * 2];\n      System.arraycopy(stack, 0, newStack, 0, stackSize);\n      stack = newStack;\n    }\n    stack[stackSize++] = newTop;\n  }\n\n  @SuppressWarnings(\"fallthrough\")\n  private JsonToken nextInArray(boolean firstElement) throws IOException {\n    if (firstElement) {\n      stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;\n    } else {\n      /* Look for a comma before each element after the first element. */\n      switch (nextNonWhitespace(true)) {\n      case ']':\n        stackSize--;\n        return token = JsonToken.END_ARRAY;\n      case ';':\n        checkLenient(); // fall-through\n      case ',':\n        break;\n      default:\n        throw syntaxError(\"Unterminated array\");\n      }\n    }\n\n    switch (nextNonWhitespace(true)) {\n    case ']':\n      if (firstElement) {\n        stackSize--;\n        return token = JsonToken.END_ARRAY;\n      }\n      // fall-through to handle \",]\"\n    case ';':\n    case ',':\n      /* In lenient mode, a 0-length literal means 'null' */\n      checkLenient();\n      pos--;\n      value = \"null\";\n      return token = JsonToken.NULL;\n    default:\n      pos--;\n      return nextValue();\n    }\n  }\n\n  @SuppressWarnings(\"fallthrough\")\n  private JsonToken nextInObject(boolean firstElement) throws IOException {\n    /*\n     * Read delimiters. Either a comma/semicolon separating this and the\n     * previous name-value pair, or a close brace to denote the end of the\n     * object.\n     */\n    if (firstElement) {\n      /* Peek to see if this is the empty object. */\n      switch (nextNonWhitespace(true)) {\n      case '}':\n        stackSize--;\n        return token = JsonToken.END_OBJECT;\n      default:\n        pos--;\n      }\n    } else {\n      switch (nextNonWhitespace(true)) {\n      case '}':\n        stackSize--;\n        return token = JsonToken.END_OBJECT;\n      case ';':\n      case ',':\n        break;\n      default:\n        throw syntaxError(\"Unterminated object\");\n      }\n    }\n\n    /* Read the name. */\n    int quote = nextNonWhitespace(true);\n    switch (quote) {\n    case '\\'':\n      checkLenient(); // fall-through\n    case '\"':\n      name = nextString((char) quote);\n      break;\n    default:\n      checkLenient();\n      pos--;\n      name = nextLiteral(false);\n      if (name.length() == 0) {\n        throw syntaxError(\"Expected name\");\n      }\n    }\n\n    stack[stackSize - 1] = JsonScope.DANGLING_NAME;\n    return token = JsonToken.NAME;\n  }\n\n  private JsonToken objectValue() throws IOException {\n    /*\n     * Read the name/value separator. Usually a colon ':'. In lenient mode\n     * we also accept an equals sign '=', or an arrow \"=>\".\n     */\n    switch (nextNonWhitespace(true)) {\n    case ':':\n      break;\n    case '=':\n      checkLenient();\n      if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>') {\n        pos++;\n      }\n      break;\n    default:\n      throw syntaxError(\"Expected ':'\");\n    }\n\n    stack[stackSize - 1] = JsonScope.NONEMPTY_OBJECT;\n    return nextValue();\n  }\n\n  @SuppressWarnings(\"fallthrough\")\n  private JsonToken nextValue() throws IOException {\n    int c = nextNonWhitespace(true);\n    switch (c) {\n    case '{':\n      push(JsonScope.EMPTY_OBJECT);\n      return token = JsonToken.BEGIN_OBJECT;\n\n    case '[':\n      push(JsonScope.EMPTY_ARRAY);\n      return token = JsonToken.BEGIN_ARRAY;\n\n    case '\\'':\n      checkLenient(); // fall-through\n    case '\"':\n      value = nextString((char) c);\n      return token = JsonToken.STRING;\n\n    default:\n      pos--;\n      return readLiteral();\n    }\n  }\n\n  /**\n   * Returns true once {@code limit - pos >= minimum}. If the data is\n   * exhausted before that many characters are available, this returns\n   * false.\n   */\n  private boolean fillBuffer(int minimum) throws IOException {\n    char[] buffer = this.buffer;\n\n    // Before clobbering the old characters, update where buffer starts\n    // Using locals here saves ~2%.\n    int line = bufferStartLine;\n    int column = bufferStartColumn;\n    for (int i = 0, p = pos; i < p; i++) {\n      if (buffer[i] == '\\n') {\n        line++;\n        column = 1;\n      } else {\n        column++;\n      }\n    }\n    bufferStartLine = line;\n    bufferStartColumn = column;\n\n    if (limit != pos) {\n      limit -= pos;\n      System.arraycopy(buffer, pos, buffer, 0, limit);\n    } else {\n      limit = 0;\n    }\n\n    pos = 0;\n    int total;\n    while ((total = in.read(buffer, limit, buffer.length - limit)) != -1) {\n      limit += total;\n\n      // if this is the first read, consume an optional byte order mark (BOM) if it exists\n      if (bufferStartLine == 1 && bufferStartColumn == 1 && limit > 0 && buffer[0] == '\\ufeff') {\n        pos++;\n        bufferStartColumn--;\n      }\n\n      if (limit >= minimum) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private int getLineNumber() {\n    int result = bufferStartLine;\n    for (int i = 0; i < pos; i++) {\n      if (buffer[i] == '\\n') {\n        result++;\n      }\n    }\n    return result;\n  }\n\n  private int getColumnNumber() {\n    int result = bufferStartColumn;\n    for (int i = 0; i < pos; i++) {\n      if (buffer[i] == '\\n') {\n        result = 1;\n      } else {\n        result++;\n      }\n    }\n    return result;\n  }\n\n  /**\n   * Returns the next character in the stream that is neither whitespace nor a\n   * part of a comment. When this returns, the returned character is always at\n   * {@code buffer[pos-1]}; this means the caller can always push back the\n   * returned character by decrementing {@code pos}.\n   */\n  private int nextNonWhitespace(boolean throwOnEof) throws IOException {\n    /*\n     * This code uses ugly local variables 'p' and 'l' representing the 'pos'\n     * and 'limit' fields respectively. Using locals rather than fields saves\n     * a few field reads for each whitespace character in a pretty-printed\n     * document, resulting in a 5% speedup. We need to flush 'p' to its field\n     * before any (potentially indirect) call to fillBuffer() and reread both\n     * 'p' and 'l' after any (potentially indirect) call to the same method.\n     */\n    char[] buffer = this.buffer;\n    int p = pos;\n    int l = limit;\n    while (true) {\n      if (p == l) {\n        pos = p;\n        if (!fillBuffer(1)) {\n          break;\n        }\n        p = pos;\n        l = limit;\n      }\n\n      int c = buffer[p++];\n      switch (c) {\n      case '\\t':\n      case ' ':\n      case '\\n':\n      case '\\r':\n        continue;\n\n      case '/':\n        pos = p;\n        if (p == l) {\n          pos--; // push back '/' so it's still in the buffer when this method returns\n          boolean charsLoaded = fillBuffer(2);\n          pos++; // consume the '/' again\n          if (!charsLoaded) {\n            return c;\n          }\n        }\n\n        checkLenient();\n        char peek = buffer[pos];\n        switch (peek) {\n        case '*':\n          // skip a /* c-style comment */\n          pos++;\n          if (!skipTo(\"*/\")) {\n            throw syntaxError(\"Unterminated comment\");\n          }\n          p = pos + 2;\n          l = limit;\n          continue;\n\n        case '/':\n          // skip a // end-of-line comment\n          pos++;\n          skipToEndOfLine();\n          p = pos;\n          l = limit;\n          continue;\n\n        default:\n          return c;\n        }\n\n      case '#':\n        pos = p;\n        /*\n         * Skip a # hash end-of-line comment. The JSON RFC doesn't\n         * specify this behaviour, but it's required to parse\n         * existing documents. See http://b/2571423.\n         */\n        checkLenient();\n        skipToEndOfLine();\n        p = pos;\n        l = limit;\n        continue;\n\n      default:\n        pos = p;\n        return c;\n      }\n    }\n    if (throwOnEof) {\n      throw new EOFException(\"End of input\"\n          + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n    } else {\n      return -1;\n    }\n  }\n\n  private void checkLenient() throws IOException {\n    if (!lenient) {\n      throw syntaxError(\"Use JsonReader.setLenient(true) to accept malformed JSON\");\n    }\n  }\n\n  /**\n   * Advances the position until after the next newline character. If the line\n   * is terminated by \"\\r\\n\", the '\\n' must be consumed as whitespace by the\n   * caller.\n   */\n  private void skipToEndOfLine() throws IOException {\n    while (pos < limit || fillBuffer(1)) {\n      char c = buffer[pos++];\n      if (c == '\\r' || c == '\\n') {\n        break;\n      }\n    }\n  }\n\n  private boolean skipTo(String toFind) throws IOException {\n    outer:\n    for (; pos + toFind.length() <= limit || fillBuffer(toFind.length()); pos++) {\n      for (int c = 0; c < toFind.length(); c++) {\n        if (buffer[pos + c] != toFind.charAt(c)) {\n          continue outer;\n        }\n      }\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * Returns the string up to but not including {@code quote}, unescaping any\n   * character escape sequences encountered along the way. The opening quote\n   * should have already been read. This consumes the closing quote, but does\n   * not include it in the returned string.\n   *\n   * @param quote either ' or \".\n   * @throws NumberFormatException if any unicode escape sequences are\n   *     malformed.\n   */\n  private String nextString(char quote) throws IOException {\n    // Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access.\n    char[] buffer = this.buffer;\n    StringBuilder builder = null;\n    while (true) {\n      int p = pos;\n      int l = limit;\n      /* the index of the first character not yet appended to the builder. */\n      int start = p;\n      while (p < l) {\n        int c = buffer[p++];\n\n        if (c == quote) {\n          pos = p;\n          if (skipping) {\n            return \"skipped!\";\n          } else if (builder == null) {\n            return stringPool.get(buffer, start, p - start - 1);\n          } else {\n            builder.append(buffer, start, p - start - 1);\n            return builder.toString();\n          }\n\n        } else if (c == '\\\\') {\n          pos = p;\n          if (builder == null) {\n            builder = new StringBuilder();\n          }\n          builder.append(buffer, start, p - start - 1);\n          builder.append(readEscapeCharacter());\n          p = pos;\n          l = limit;\n          start = p;\n        }\n      }\n\n      if (builder == null) {\n        builder = new StringBuilder();\n      }\n      builder.append(buffer, start, p - start);\n      pos = p;\n      if (!fillBuffer(1)) {\n        throw syntaxError(\"Unterminated string\");\n      }\n    }\n  }\n\n  /**\n   * Reads the value up to but not including any delimiter characters. This\n   * does not consume the delimiter character.\n   *\n   * @param assignOffsetsOnly true for this method to only set the valuePos\n   *     and valueLength fields and return a null result. This only works if\n   *     the literal is short; a string is returned otherwise.\n   */\n  @SuppressWarnings(\"fallthrough\")\n  private String nextLiteral(boolean assignOffsetsOnly) throws IOException {\n    StringBuilder builder = null;\n    valuePos = -1;\n    valueLength = 0;\n    int i = 0;\n\n    findNonLiteralCharacter:\n    while (true) {\n      for (; pos + i < limit; i++) {\n        switch (buffer[pos + i]) {\n        case '/':\n        case '\\\\':\n        case ';':\n        case '#':\n        case '=':\n            checkLenient(); // fall-through\n        case '{':\n        case '}':\n        case '[':\n        case ']':\n        case ':':\n        case ',':\n        case ' ':\n        case '\\t':\n        case '\\f':\n        case '\\r':\n        case '\\n':\n            break findNonLiteralCharacter;\n        }\n      }\n\n      /*\n       * Attempt to load the entire literal into the buffer at once. If\n       * we run out of input, add a non-literal character at the end so\n       * that decoding doesn't need to do bounds checks.\n       */\n      if (i < buffer.length) {\n        if (fillBuffer(i + 1)) {\n          continue;\n        } else {\n          buffer[limit] = '\\0';\n          break;\n        }\n      }\n\n      // use a StringBuilder when the value is too long. It must be an unquoted string.\n      if (builder == null) {\n        builder = new StringBuilder();\n      }\n      builder.append(buffer, pos, i);\n      valueLength += i;\n      pos += i;\n      i = 0;\n      if (!fillBuffer(1)) {\n        break;\n      }\n    }\n\n    String result;\n    if (assignOffsetsOnly && builder == null) {\n      valuePos = pos;\n      result = null;\n    } else if (skipping) {\n      result = \"skipped!\";\n    } else if (builder == null) {\n      result = stringPool.get(buffer, pos, i);\n    } else {\n      builder.append(buffer, pos, i);\n      result = builder.toString();\n    }\n    valueLength += i;\n    pos += i;\n    return result;\n  }\n\n  @Override\n  public String toString() {\n    return getClass().getSimpleName()\n        + \" at line \" + getLineNumber() + \" column \" + getColumnNumber();\n  }\n\n  /**\n   * Unescapes the character identified by the character or characters that\n   * immediately follow a backslash. The backslash '\\' should have already\n   * been read. This supports both unicode escapes \"u000A\" and two-character\n   * escapes \"\\n\".\n   *\n   * @throws NumberFormatException if any unicode escape sequences are\n   *     malformed.\n   */\n  private char readEscapeCharacter() throws IOException {\n    if (pos == limit && !fillBuffer(1)) {\n      throw syntaxError(\"Unterminated escape sequence\");\n    }\n\n    char escaped = buffer[pos++];\n    switch (escaped) {\n    case 'u':\n      if (pos + 4 > limit && !fillBuffer(4)) {\n        throw syntaxError(\"Unterminated escape sequence\");\n      }\n      // Equivalent to Integer.parseInt(stringPool.get(buffer, pos, 4), 16);\n      char result = 0;\n      for (int i = pos, end = i + 4; i < end; i++) {\n        char c = buffer[i];\n        result <<= 4;\n        if (c >= '0' && c <= '9') {\n          result += (c - '0');\n        } else if (c >= 'a' && c <= 'f') {\n          result += (c - 'a' + 10);\n        } else if (c >= 'A' && c <= 'F') {\n          result += (c - 'A' + 10);\n        } else {\n          throw new NumberFormatException(\"\\\\u\" + stringPool.get(buffer, pos, 4));\n        }\n      }\n      pos += 4;\n      return result;\n\n    case 't':\n      return '\\t';\n\n    case 'b':\n      return '\\b';\n\n    case 'n':\n      return '\\n';\n\n    case 'r':\n      return '\\r';\n\n    case 'f':\n      return '\\f';\n\n    case '\\'':\n    case '\"':\n    case '\\\\':\n    default:\n      return escaped;\n    }\n  }\n\n  /**\n   * Reads a null, boolean, numeric or unquoted string literal value.\n   */\n  private JsonToken readLiteral() throws IOException {\n    value = nextLiteral(true);\n    if (valueLength == 0) {\n      throw syntaxError(\"Expected literal value\");\n    }\n    token = decodeLiteral();\n    if (token == JsonToken.STRING) {\n      checkLenient();\n    }\n    return token;\n  }\n\n  /**\n   * Assigns {@code nextToken} based on the value of {@code nextValue}.\n   */\n  private JsonToken decodeLiteral() throws IOException {\n    if (valuePos == -1) {\n      // it was too long to fit in the buffer so it can only be a string\n      return JsonToken.STRING;\n    } else if (valueLength == 4\n        && ('n' == buffer[valuePos    ] || 'N' == buffer[valuePos    ])\n        && ('u' == buffer[valuePos + 1] || 'U' == buffer[valuePos + 1])\n        && ('l' == buffer[valuePos + 2] || 'L' == buffer[valuePos + 2])\n        && ('l' == buffer[valuePos + 3] || 'L' == buffer[valuePos + 3])) {\n      value = \"null\";\n      return JsonToken.NULL;\n    } else if (valueLength == 4\n        && ('t' == buffer[valuePos    ] || 'T' == buffer[valuePos    ])\n        && ('r' == buffer[valuePos + 1] || 'R' == buffer[valuePos + 1])\n        && ('u' == buffer[valuePos + 2] || 'U' == buffer[valuePos + 2])\n        && ('e' == buffer[valuePos + 3] || 'E' == buffer[valuePos + 3])) {\n      value = TRUE;\n      return JsonToken.BOOLEAN;\n    } else if (valueLength == 5\n        && ('f' == buffer[valuePos    ] || 'F' == buffer[valuePos    ])\n        && ('a' == buffer[valuePos + 1] || 'A' == buffer[valuePos + 1])\n        && ('l' == buffer[valuePos + 2] || 'L' == buffer[valuePos + 2])\n        && ('s' == buffer[valuePos + 3] || 'S' == buffer[valuePos + 3])\n        && ('e' == buffer[valuePos + 4] || 'E' == buffer[valuePos + 4])) {\n      value = FALSE;\n      return JsonToken.BOOLEAN;\n    } else {\n      value = stringPool.get(buffer, valuePos, valueLength);\n      return decodeNumber(buffer, valuePos, valueLength);\n    }\n  }\n\n  /**\n   * Determine whether the characters is a JSON number. Numbers are of the\n   * form -12.34e+56. Fractional and exponential parts are optional. Leading\n   * zeroes are not allowed in the value or exponential part, but are allowed\n   * in the fraction.\n   */\n  private JsonToken decodeNumber(char[] chars, int offset, int length) {\n    int i = offset;\n    int c = chars[i];\n\n    if (c == '-') {\n      c = chars[++i];\n    }\n\n    if (c == '0') {\n      c = chars[++i];\n    } else if (c >= '1' && c <= '9') {\n      c = chars[++i];\n      while (c >= '0' && c <= '9') {\n        c = chars[++i];\n      }\n    } else {\n      return JsonToken.STRING;\n    }\n\n    if (c == '.') {\n      c = chars[++i];\n      while (c >= '0' && c <= '9') {\n        c = chars[++i];\n      }\n    }\n\n    if (c == 'e' || c == 'E') {\n      c = chars[++i];\n      if (c == '+' || c == '-') {\n        c = chars[++i];\n      }\n      if (c >= '0' && c <= '9') {\n        c = chars[++i];\n        while (c >= '0' && c <= '9') {\n          c = chars[++i];\n        }\n      } else {\n        return JsonToken.STRING;\n      }\n    }\n\n    if (i == offset + length) {\n      return JsonToken.NUMBER;\n    } else {\n      return JsonToken.STRING;\n    }\n  }\n\n  /**\n   * Throws a new IO exception with the given message and a context snippet\n   * with this reader's content.\n   */\n  private IOException syntaxError(String message) throws IOException {\n    throw new MalformedJsonException(message\n        + \" at line \" + getLineNumber() + \" column \" + getColumnNumber());\n  }\n\n  static {\n    JsonReaderInternalAccess.INSTANCE = new JsonReaderInternalAccess() {\n      @Override\n      public void promoteNameToValue(JsonReader reader) throws IOException {\n        if (reader instanceof JsonTreeReader) {\n          ((JsonTreeReader)reader).promoteNameToValue();\n          return;\n        }\n        reader.peek();\n        if (reader.token != JsonToken.NAME) {\n          throw new IllegalStateException(\"Expected a name but was \" + reader.peek() + \" \"\n              + \" at line \" + reader.getLineNumber() + \" column \" + reader.getColumnNumber());\n        }\n        reader.value = reader.name;\n        reader.name = null;\n        reader.token = JsonToken.STRING;\n      }\n    };\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/stream/JsonScope.java",
    "content": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.stream;\n\n/**\n * Lexical scoping elements within a JSON reader or writer.\n *\n * @author Jesse Wilson\n * @since 1.6\n */\nenum JsonScope {\n\n    /**\n     * An array with no elements requires no separators or newlines before\n     * it is closed.\n     */\n    EMPTY_ARRAY,\n\n    /**\n     * A array with at least one value requires a comma and newline before\n     * the next element.\n     */\n    NONEMPTY_ARRAY,\n\n    /**\n     * An object with no name/value pairs requires no separators or newlines\n     * before it is closed.\n     */\n    EMPTY_OBJECT,\n\n    /**\n     * An object whose most recent element is a key. The next element must\n     * be a value.\n     */\n    DANGLING_NAME,\n\n    /**\n     * An object with at least one name/value pair requires a comma and\n     * newline before the next element.\n     */\n    NONEMPTY_OBJECT,\n\n    /**\n     * No object or array has been started.\n     */\n    EMPTY_DOCUMENT,\n\n    /**\n     * A document with at an array or object.\n     */\n    NONEMPTY_DOCUMENT,\n\n    /**\n     * A document that's been closed and cannot be accessed.\n     */\n    CLOSED,\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/stream/JsonToken.java",
    "content": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.stream;\n\n/**\n * A structure, name or value type in a JSON-encoded string.\n *\n * @author Jesse Wilson\n * @since 1.6\n */\npublic enum JsonToken {\n\n  /**\n   * The opening of a JSON array. Written using {@link JsonWriter#beginObject}\n   * and read using {@link JsonReader#beginObject}.\n   */\n  BEGIN_ARRAY,\n\n  /**\n   * The closing of a JSON array. Written using {@link JsonWriter#endArray}\n   * and read using {@link JsonReader#endArray}.\n   */\n  END_ARRAY,\n\n  /**\n   * The opening of a JSON object. Written using {@link JsonWriter#beginObject}\n   * and read using {@link JsonReader#beginObject}.\n   */\n  BEGIN_OBJECT,\n\n  /**\n   * The closing of a JSON object. Written using {@link JsonWriter#endObject}\n   * and read using {@link JsonReader#endObject}.\n   */\n  END_OBJECT,\n\n  /**\n   * A JSON property name. Within objects, tokens alternate between names and\n   * their values. Written using {@link JsonWriter#name} and read using {@link\n   * JsonReader#nextName}\n   */\n  NAME,\n\n  /**\n   * A JSON string.\n   */\n  STRING,\n\n  /**\n   * A JSON number represented in this API by a Java {@code double}, {@code\n   * long}, or {@code int}.\n   */\n  NUMBER,\n\n  /**\n   * A JSON {@code true} or {@code false}.\n   */\n  BOOLEAN,\n\n  /**\n   * A JSON {@code null}.\n   */\n  NULL,\n\n  /**\n   * The end of the JSON stream. This sentinel value is returned by {@link\n   * JsonReader#peek()} to signal that the JSON-encoded value has no more\n   * tokens.\n   */\n  END_DOCUMENT\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/stream/JsonWriter.java",
    "content": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.stream;\n\nimport java.io.Closeable;\nimport java.io.Flushable;\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Writes a JSON (<a href=\"http://www.ietf.org/rfc/rfc4627.txt\">RFC 4627</a>)\n * encoded value to a stream, one token at a time. The stream includes both\n * literal values (strings, numbers, booleans and nulls) as well as the begin\n * and end delimiters of objects and arrays.\n *\n * <h3>Encoding JSON</h3>\n * To encode your data as JSON, create a new {@code JsonWriter}. Each JSON\n * document must contain one top-level array or object. Call methods on the\n * writer as you walk the structure's contents, nesting arrays and objects as\n * necessary:\n * <ul>\n *   <li>To write <strong>arrays</strong>, first call {@link #beginArray()}.\n *       Write each of the array's elements with the appropriate {@link #value}\n *       methods or by nesting other arrays and objects. Finally close the array\n *       using {@link #endArray()}.\n *   <li>To write <strong>objects</strong>, first call {@link #beginObject()}.\n *       Write each of the object's properties by alternating calls to\n *       {@link #name} with the property's value. Write property values with the\n *       appropriate {@link #value} method or by nesting other objects or arrays.\n *       Finally close the object using {@link #endObject()}.\n * </ul>\n *\n * <h3>Example</h3>\n * Suppose we'd like to encode a stream of messages such as the following: <pre> {@code\n * [\n *   {\n *     \"id\": 912345678901,\n *     \"text\": \"How do I stream JSON in Java?\",\n *     \"geo\": null,\n *     \"user\": {\n *       \"name\": \"json_newb\",\n *       \"followers_count\": 41\n *      }\n *   },\n *   {\n *     \"id\": 912345678902,\n *     \"text\": \"@json_newb just use JsonWriter!\",\n *     \"geo\": [50.454722, -104.606667],\n *     \"user\": {\n *       \"name\": \"jesse\",\n *       \"followers_count\": 2\n *     }\n *   }\n * ]}</pre>\n * This code encodes the above structure: <pre>   {@code\n *   public void writeJsonStream(OutputStream out, List<Message> messages) throws IOException {\n *     JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, \"UTF-8\"));\n *     writer.setIndentSpaces(4);\n *     writeMessagesArray(writer, messages);\n *     writer.close();\n *   }\n *\n *   public void writeMessagesArray(JsonWriter writer, List<Message> messages) throws IOException {\n *     writer.beginArray();\n *     for (Message message : messages) {\n *       writeMessage(writer, message);\n *     }\n *     writer.endArray();\n *   }\n *\n *   public void writeMessage(JsonWriter writer, Message message) throws IOException {\n *     writer.beginObject();\n *     writer.name(\"id\").value(message.getId());\n *     writer.name(\"text\").value(message.getText());\n *     if (message.getGeo() != null) {\n *       writer.name(\"geo\");\n *       writeDoublesArray(writer, message.getGeo());\n *     } else {\n *       writer.name(\"geo\").nullValue();\n *     }\n *     writer.name(\"user\");\n *     writeUser(writer, message.getUser());\n *     writer.endObject();\n *   }\n *\n *   public void writeUser(JsonWriter writer, User user) throws IOException {\n *     writer.beginObject();\n *     writer.name(\"name\").value(user.getName());\n *     writer.name(\"followers_count\").value(user.getFollowersCount());\n *     writer.endObject();\n *   }\n *\n *   public void writeDoublesArray(JsonWriter writer, List<Double> doubles) throws IOException {\n *     writer.beginArray();\n *     for (Double value : doubles) {\n *       writer.value(value);\n *     }\n *     writer.endArray();\n *   }}</pre>\n *\n * <p>Each {@code JsonWriter} may be used to write a single JSON stream.\n * Instances of this class are not thread safe. Calls that would result in a\n * malformed JSON string will fail with an {@link IllegalStateException}.\n *\n * @author Jesse Wilson\n * @since 1.6\n */\npublic class JsonWriter implements Closeable, Flushable {\n\n  /*\n   * From RFC 4627, \"All Unicode characters may be placed within the\n   * quotation marks except for the characters that must be escaped:\n   * quotation mark, reverse solidus, and the control characters\n   * (U+0000 through U+001F).\"\n   *\n   * We also escape '\\u2028' and '\\u2029', which JavaScript interprets as\n   * newline characters. This prevents eval() from failing with a syntax\n   * error. http://code.google.com/p/google-gson/issues/detail?id=341\n   */\n  private static final String[] REPLACEMENT_CHARS;\n  private static final String[] HTML_SAFE_REPLACEMENT_CHARS;\n  static {\n    REPLACEMENT_CHARS = new String[128];\n    for (int i = 0; i <= 0x1f; i++) {\n      REPLACEMENT_CHARS[i] = String.format(\"\\\\u%04x\", (int) i);\n    }\n    REPLACEMENT_CHARS['\"'] = \"\\\\\\\"\";\n    REPLACEMENT_CHARS['\\\\'] = \"\\\\\\\\\";\n    REPLACEMENT_CHARS['\\t'] = \"\\\\t\";\n    REPLACEMENT_CHARS['\\b'] = \"\\\\b\";\n    REPLACEMENT_CHARS['\\n'] = \"\\\\n\";\n    REPLACEMENT_CHARS['\\r'] = \"\\\\r\";\n    REPLACEMENT_CHARS['\\f'] = \"\\\\f\";\n    HTML_SAFE_REPLACEMENT_CHARS = REPLACEMENT_CHARS.clone();\n    HTML_SAFE_REPLACEMENT_CHARS['<'] = \"\\\\u003c\";\n    HTML_SAFE_REPLACEMENT_CHARS['>'] = \"\\\\u003e\";\n    HTML_SAFE_REPLACEMENT_CHARS['&'] = \"\\\\u0026\";\n    HTML_SAFE_REPLACEMENT_CHARS['='] = \"\\\\u003d\";\n    HTML_SAFE_REPLACEMENT_CHARS['\\''] = \"\\\\u0027\";\n  }\n\n  /** The output data, containing at most one top-level array or object. */\n  private final Writer out;\n\n  private final List<JsonScope> stack = new ArrayList<JsonScope>();\n  {\n    stack.add(JsonScope.EMPTY_DOCUMENT);\n  }\n\n  /**\n   * A string containing a full set of spaces for a single level of\n   * indentation, or null for no pretty printing.\n   */\n  private String indent;\n\n  /**\n   * The name/value separator; either \":\" or \": \".\n   */\n  private String separator = \":\";\n\n  private boolean lenient;\n\n  private boolean htmlSafe;\n\n  private String deferredName;\n\n  private boolean serializeNulls = true;\n\n  /**\n   * Creates a new instance that writes a JSON-encoded stream to {@code out}.\n   * For best performance, ensure {@link Writer} is buffered; wrapping in\n   * {@link java.io.BufferedWriter BufferedWriter} if necessary.\n   */\n  public JsonWriter(Writer out) {\n    if (out == null) {\n      throw new NullPointerException(\"out == null\");\n    }\n    this.out = out;\n  }\n\n  /**\n   * Sets the indentation string to be repeated for each level of indentation\n   * in the encoded document. If {@code indent.isEmpty()} the encoded document\n   * will be compact. Otherwise the encoded document will be more\n   * human-readable.\n   *\n   * @param indent a string containing only whitespace.\n   */\n  public final void setIndent(String indent) {\n    if (indent.length() == 0) {\n      this.indent = null;\n      this.separator = \":\";\n    } else {\n      this.indent = indent;\n      this.separator = \": \";\n    }\n  }\n\n  /**\n   * Configure this writer to relax its syntax rules. By default, this writer\n   * only emits well-formed JSON as specified by <a\n   * href=\"http://www.ietf.org/rfc/rfc4627.txt\">RFC 4627</a>. Setting the writer\n   * to lenient permits the following:\n   * <ul>\n   *   <li>Top-level values of any type. With strict writing, the top-level\n   *       value must be an object or an array.\n   *   <li>Numbers may be {@link Double#isNaN() NaNs} or {@link\n   *       Double#isInfinite() infinities}.\n   * </ul>\n   */\n  public final void setLenient(boolean lenient) {\n    this.lenient = lenient;\n  }\n\n  /**\n   * Returns true if this writer has relaxed syntax rules.\n   */\n  public boolean isLenient() {\n    return lenient;\n  }\n\n  /**\n   * Configure this writer to emit JSON that's safe for direct inclusion in HTML\n   * and XML documents. This escapes the HTML characters {@code <}, {@code >},\n   * {@code &} and {@code =} before writing them to the stream. Without this\n   * setting, your XML/HTML encoder should replace these characters with the\n   * corresponding escape sequences.\n   */\n  public final void setHtmlSafe(boolean htmlSafe) {\n    this.htmlSafe = htmlSafe;\n  }\n\n  /**\n   * Returns true if this writer writes JSON that's safe for inclusion in HTML\n   * and XML documents.\n   */\n  public final boolean isHtmlSafe() {\n    return htmlSafe;\n  }\n\n  /**\n   * Sets whether object members are serialized when their value is null.\n   * This has no impact on array elements. The default is true.\n   */\n  public final void setSerializeNulls(boolean serializeNulls) {\n    this.serializeNulls = serializeNulls;\n  }\n\n  /**\n   * Returns true if object members are serialized when their value is null.\n   * This has no impact on array elements. The default is true.\n   */\n  public final boolean getSerializeNulls() {\n    return serializeNulls;\n  }\n\n  /**\n   * Begins encoding a new array. Each call to this method must be paired with\n   * a call to {@link #endArray}.\n   *\n   * @return this writer.\n   */\n  public JsonWriter beginArray() throws IOException {\n    writeDeferredName();\n    return open(JsonScope.EMPTY_ARRAY, \"[\");\n  }\n\n  /**\n   * Ends encoding the current array.\n   *\n   * @return this writer.\n   */\n  public JsonWriter endArray() throws IOException {\n    return close(JsonScope.EMPTY_ARRAY, JsonScope.NONEMPTY_ARRAY, \"]\");\n  }\n\n  /**\n   * Begins encoding a new object. Each call to this method must be paired\n   * with a call to {@link #endObject}.\n   *\n   * @return this writer.\n   */\n  public JsonWriter beginObject() throws IOException {\n    writeDeferredName();\n    return open(JsonScope.EMPTY_OBJECT, \"{\");\n  }\n\n  /**\n   * Ends encoding the current object.\n   *\n   * @return this writer.\n   */\n  public JsonWriter endObject() throws IOException {\n    return close(JsonScope.EMPTY_OBJECT, JsonScope.NONEMPTY_OBJECT, \"}\");\n  }\n\n  /**\n   * Enters a new scope by appending any necessary whitespace and the given\n   * bracket.\n   */\n  private JsonWriter open(JsonScope empty, String openBracket) throws IOException {\n    beforeValue(true);\n    stack.add(empty);\n    out.write(openBracket);\n    return this;\n  }\n\n  /**\n   * Closes the current scope by appending any necessary whitespace and the\n   * given bracket.\n   */\n  private JsonWriter close(JsonScope empty, JsonScope nonempty, String closeBracket)\n      throws IOException {\n    JsonScope context = peek();\n    if (context != nonempty && context != empty) {\n      throw new IllegalStateException(\"Nesting problem: \" + stack);\n    }\n    if (deferredName != null) {\n      throw new IllegalStateException(\"Dangling name: \" + deferredName);\n    }\n\n    stack.remove(stack.size() - 1);\n    if (context == nonempty) {\n      newline();\n    }\n    out.write(closeBracket);\n    return this;\n  }\n\n  /**\n   * Returns the value on the top of the stack.\n   */\n  private JsonScope peek() {\n    int size = stack.size();\n    if (size == 0) {\n      throw new IllegalStateException(\"JsonWriter is closed.\");\n    }\n    return stack.get(size - 1);\n  }\n\n  /**\n   * Replace the value on the top of the stack with the given value.\n   */\n  private void replaceTop(JsonScope topOfStack) {\n    stack.set(stack.size() - 1, topOfStack);\n  }\n\n  /**\n   * Encodes the property name.\n   *\n   * @param name the name of the forthcoming value. May not be null.\n   * @return this writer.\n   */\n  public JsonWriter name(String name) throws IOException {\n    if (name == null) {\n      throw new NullPointerException(\"name == null\");\n    }\n    if (deferredName != null) {\n      throw new IllegalStateException();\n    }\n    if (stack.isEmpty()) {\n      throw new IllegalStateException(\"JsonWriter is closed.\");\n    }\n    deferredName = name;\n    return this;\n  }\n\n  private void writeDeferredName() throws IOException {\n    if (deferredName != null) {\n      beforeName();\n      string(deferredName);\n      deferredName = null;\n    }\n  }\n\n  /**\n   * Encodes {@code value}.\n   *\n   * @param value the literal string value, or null to encode a null literal.\n   * @return this writer.\n   */\n  public JsonWriter value(String value) throws IOException {\n    if (value == null) {\n      return nullValue();\n    }\n    writeDeferredName();\n    beforeValue(false);\n    string(value);\n    return this;\n  }\n\n  /**\n   * Encodes {@code null}.\n   *\n   * @return this writer.\n   */\n  public JsonWriter nullValue() throws IOException {\n    if (deferredName != null) {\n      if (serializeNulls) {\n        writeDeferredName();\n      } else {\n        deferredName = null;\n        return this; // skip the name and the value\n      }\n    }\n    beforeValue(false);\n    out.write(\"null\");\n    return this;\n  }\n\n  /**\n   * Encodes {@code value}.\n   *\n   * @return this writer.\n   */\n  public JsonWriter value(boolean value) throws IOException {\n    writeDeferredName();\n    beforeValue(false);\n    out.write(value ? \"true\" : \"false\");\n    return this;\n  }\n\n  /**\n   * Encodes {@code value}.\n   *\n   * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n   *     {@link Double#isInfinite() infinities}.\n   * @return this writer.\n   */\n  public JsonWriter value(double value) throws IOException {\n    if (Double.isNaN(value) || Double.isInfinite(value)) {\n      throw new IllegalArgumentException(\"Numeric values must be finite, but was \" + value);\n    }\n    writeDeferredName();\n    beforeValue(false);\n    out.append(Double.toString(value));\n    return this;\n  }\n\n  /**\n   * Encodes {@code value}.\n   *\n   * @return this writer.\n   */\n  public JsonWriter value(long value) throws IOException {\n    writeDeferredName();\n    beforeValue(false);\n    out.write(Long.toString(value));\n    return this;\n  }\n\n  /**\n   * Encodes {@code value}.\n   *\n   * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n   *     {@link Double#isInfinite() infinities}.\n   * @return this writer.\n   */\n  public JsonWriter value(Number value) throws IOException {\n    if (value == null) {\n      return nullValue();\n    }\n\n    writeDeferredName();\n    String string = value.toString();\n    if (!lenient\n        && (string.equals(\"-Infinity\") || string.equals(\"Infinity\") || string.equals(\"NaN\"))) {\n      throw new IllegalArgumentException(\"Numeric values must be finite, but was \" + value);\n    }\n    beforeValue(false);\n    out.append(string);\n    return this;\n  }\n\n  /**\n   * Ensures all buffered data is written to the underlying {@link Writer}\n   * and flushes that writer.\n   */\n  public void flush() throws IOException {\n    if (stack.isEmpty()) {\n      throw new IllegalStateException(\"JsonWriter is closed.\");\n    }\n    out.flush();\n  }\n\n  /**\n   * Flushes and closes this writer and the underlying {@link Writer}.\n   *\n   * @throws IOException if the JSON document is incomplete.\n   */\n  public void close() throws IOException {\n    out.close();\n\n    int size = stack.size();\n    if (size > 1 || size == 1 && stack.get(size - 1) != JsonScope.NONEMPTY_DOCUMENT) {\n      throw new IOException(\"Incomplete document\");\n    }\n    stack.clear();\n  }\n\n  private void string(String value) throws IOException {\n    String[] replacements = htmlSafe ? HTML_SAFE_REPLACEMENT_CHARS : REPLACEMENT_CHARS;\n    out.write(\"\\\"\");\n    int last = 0;\n    int length = value.length();\n    for (int i = 0; i < length; i++) {\n      char c = value.charAt(i);\n      String replacement;\n      if (c < 128) {\n        replacement = replacements[c];\n        if (replacement == null) {\n          continue;\n        }\n      } else if (c == '\\u2028') {\n        replacement = \"\\\\u2028\";\n      } else if (c == '\\u2029') {\n        replacement = \"\\\\u2029\";\n      } else {\n        continue;\n      }\n      if (last < i) {\n        out.write(value, last, i - last);\n      }\n      out.write(replacement);\n      last = i + 1;\n    }\n    if (last < length) {\n      out.write(value, last, length - last);\n    }\n    out.write(\"\\\"\");\n  }\n\n  private void newline() throws IOException {\n    if (indent == null) {\n      return;\n    }\n\n    out.write(\"\\n\");\n    for (int i = 1; i < stack.size(); i++) {\n      out.write(indent);\n    }\n  }\n\n  /**\n   * Inserts any necessary separators and whitespace before a name. Also\n   * adjusts the stack to expect the name's value.\n   */\n  private void beforeName() throws IOException {\n    JsonScope context = peek();\n    if (context == JsonScope.NONEMPTY_OBJECT) { // first in object\n      out.write(',');\n    } else if (context != JsonScope.EMPTY_OBJECT) { // not in an object!\n      throw new IllegalStateException(\"Nesting problem: \" + stack);\n    }\n    newline();\n    replaceTop(JsonScope.DANGLING_NAME);\n  }\n\n  /**\n   * Inserts any necessary separators and whitespace before a literal value,\n   * inline array, or inline object. Also adjusts the stack to expect either a\n   * closing bracket or another element.\n   *\n   * @param root true if the value is a new array or object, the two values\n   *     permitted as top-level elements.\n   */\n  @SuppressWarnings(\"fallthrough\")\n  private void beforeValue(boolean root) throws IOException {\n    switch (peek()) {\n    case NONEMPTY_DOCUMENT:\n      if (!lenient) {\n        throw new IllegalStateException(\n            \"JSON must have only one top-level value.\");\n      }\n      // fall-through\n    case EMPTY_DOCUMENT: // first in document\n      if (!lenient && !root) {\n        throw new IllegalStateException(\n            \"JSON must start with an array or an object.\");\n      }\n      replaceTop(JsonScope.NONEMPTY_DOCUMENT);\n      break;\n\n    case EMPTY_ARRAY: // first in array\n      replaceTop(JsonScope.NONEMPTY_ARRAY);\n      newline();\n      break;\n\n    case NONEMPTY_ARRAY: // another in array\n      out.append(',');\n      newline();\n      break;\n\n    case DANGLING_NAME: // value for name\n      out.append(separator);\n      replaceTop(JsonScope.NONEMPTY_OBJECT);\n      break;\n\n    default:\n      throw new IllegalStateException(\"Nesting problem: \" + stack);\n    }\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/stream/MalformedJsonException.java",
    "content": "/*\n * Copyright (C) 2010 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.stream;\n\nimport java.io.IOException;\n\n/**\n * Thrown when a reader encounters malformed JSON. Some syntax errors can be\n * ignored by calling {@link JsonReader#setLenient(boolean)}.\n */\npublic final class MalformedJsonException extends IOException {\n  private static final long serialVersionUID = 1L;\n\n  public MalformedJsonException(String msg) {\n    super(msg);\n  }\n\n  public MalformedJsonException(String msg, Throwable throwable) {\n    super(msg);\n    // Using initCause() instead of calling super() because Java 1.5 didn't retrofit IOException\n    // with a constructor with Throwable. This was done in Java 1.6\n    initCause(throwable);\n  }\n\n  public MalformedJsonException(Throwable throwable) {\n    // Using initCause() instead of calling super() because Java 1.5 didn't retrofit IOException\n    // with a constructor with Throwable. This was done in Java 1.6\n    initCause(throwable);\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/gson/stream/StringPool.java",
    "content": "/*\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.gson.stream;\n\n/**\n * A pool of string instances. Unlike the {@link String#intern() VM's\n * interned strings}, this pool provides no guarantee of reference equality.\n * It is intended only to save allocations. This class is not thread safe.\n */\nfinal class StringPool {\n\n  private final String[] pool = new String[512];\n\n  /**\n   * Returns a string equal to {@code new String(array, start, length)}.\n   */\n  public String get(char[] array, int start, int length) {\n    // Compute an arbitrary hash of the content\n    int hashCode = 0;\n    for (int i = start; i < start + length; i++) {\n      hashCode = (hashCode * 31) + array[i];\n    }\n\n    // Pick a bucket using Doug Lea's supplemental secondaryHash function (from HashMap)\n    hashCode ^= (hashCode >>> 20) ^ (hashCode >>> 12);\n    hashCode ^= (hashCode >>> 7) ^ (hashCode >>> 4);\n    int index = hashCode & (pool.length - 1);\n\n    String pooled = pool[index];\n    if (pooled == null || pooled.length() != length) {\n      String result = new String(array, start, length);\n      pool[index] = result;\n      return result;\n    }\n\n    for (int i = 0; i < length; i++) {\n      if (pooled.charAt(i) != array[start + i]) {\n        String result = new String(array, start, length);\n        pool[index] = result;\n        return result;\n      }\n    }\n\n    return pooled;\n  }\n}"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/AuthFailureError.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\nimport android.content.Intent;\n\n/**\n * Error indicating that there was an authentication failure when performing a Request.\n */\n@SuppressWarnings(\"serial\")\npublic class AuthFailureError extends VolleyError {\n    /** An intent that can be used to resolve this exception. (Brings up the password dialog.) */\n    private Intent mResolutionIntent;\n\n    public AuthFailureError() { }\n\n    public AuthFailureError(Intent intent) {\n        mResolutionIntent = intent;\n    }\n\n    public AuthFailureError(NetworkResponse response) {\n        super(response);\n    }\n\n    public AuthFailureError(String message) {\n        super(message);\n    }\n\n    public AuthFailureError(String message, Exception reason) {\n        super(message, reason);\n    }\n\n    public Intent getResolutionIntent() {\n        return mResolutionIntent;\n    }\n\n    @Override\n    public String getMessage() {\n        if (mResolutionIntent != null) {\n            return \"User needs to (re)enter credentials.\";\n        }\n        return super.getMessage();\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/Cache.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\nimport java.util.Collections;\nimport java.util.Map;\n\n/**\n * An interface for a cache keyed by a String with a byte array as data.\n */\npublic interface Cache {\n    /**\n     * Retrieves an entry from the cache.\n     * @param key Cache key\n     * @return An {@link Entry} or null in the event of a cache miss\n     */\n    public Entry get(String key);\n\n    /**\n     * Adds or replaces an entry to the cache.\n     * @param key Cache key\n     * @param entry Data to store and metadata for cache coherency, TTL, etc.\n     */\n    public void put(String key, Entry entry);\n\n    /**\n     * Performs any potentially long-running actions needed to initialize the cache;\n     * will be called from a worker thread.\n     */\n    public void initialize();\n\n    /**\n     * Invalidates an entry in the cache.\n     * @param key Cache key\n     * @param fullExpire True to fully expire the entry, false to soft expire\n     */\n    public void invalidate(String key, boolean fullExpire);\n\n    /**\n     * Removes an entry from the cache.\n     * @param key Cache key\n     */\n    public void remove(String key);\n\n    /**\n     * Empties the cache.\n     */\n    public void clear();\n\n    /**\n     * Data and metadata for an entry returned by the cache.\n     */\n    public static class Entry {\n        /** The data returned from cache. */\n        public byte[] data;\n\n        /** ETag for cache coherency. */\n        public String etag;\n\n        /** Date of this response as reported by the server. */\n        public long serverDate;\n\n        /** The last modified date for the requested object. */\n        public long lastModified;\n\n        /** TTL for this record. */\n        public long ttl;\n\n        /** Soft TTL for this record. */\n        public long softTtl;\n\n        /** Immutable response headers as received from server; must be non-null. */\n        public Map<String, String> responseHeaders = Collections.emptyMap();\n\n        /** True if the entry is expired. */\n        public boolean isExpired() {\n            return this.ttl < System.currentTimeMillis();\n        }\n\n        /** True if a refresh is needed from the original data source. */\n        public boolean refreshNeeded() {\n            return this.softTtl < System.currentTimeMillis();\n        }\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/CacheDispatcher.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\nimport android.os.Process;\n\nimport java.util.concurrent.BlockingQueue;\n\n/**\n * Provides a thread for performing cache triage on a queue of requests.\n *\n * Requests added to the specified cache queue are resolved from cache.\n * Any deliverable response is posted back to the caller via a\n * {@link ResponseDelivery}.  Cache misses and responses that require\n * refresh are enqueued on the specified network queue for processing\n * by a {@link NetworkDispatcher}.\n */\npublic class CacheDispatcher extends Thread {\n\n    private static final boolean DEBUG = VolleyLog.DEBUG;\n\n    /** The queue of requests coming in for triage. */\n    private final BlockingQueue<Request<?>> mCacheQueue;\n\n    /** The queue of requests going out to the network. */\n    private final BlockingQueue<Request<?>> mNetworkQueue;\n\n    /** The cache to read from. */\n    private final Cache mCache;\n\n    /** For posting responses. */\n    private final ResponseDelivery mDelivery;\n\n    /** Used for telling us to die. */\n    private volatile boolean mQuit = false;\n\n    /**\n     * Creates a new cache triage dispatcher thread.  You must call {@link #start()}\n     * in order to begin processing.\n     *\n     * @param cacheQueue Queue of incoming requests for triage\n     * @param networkQueue Queue to post requests that require network to\n     * @param cache Cache interface to use for resolution\n     * @param delivery Delivery interface to use for posting responses\n     */\n    public CacheDispatcher(\n            BlockingQueue<Request<?>> cacheQueue, BlockingQueue<Request<?>> networkQueue,\n            Cache cache, ResponseDelivery delivery) {\n        mCacheQueue = cacheQueue;\n        mNetworkQueue = networkQueue;\n        mCache = cache;\n        mDelivery = delivery;\n    }\n\n    /**\n     * Forces this dispatcher to quit immediately.  If any requests are still in\n     * the queue, they are not guaranteed to be processed.\n     */\n    public void quit() {\n        mQuit = true;\n        interrupt();\n    }\n\n    @Override\n    public void run() {\n        if (DEBUG) VolleyLog.v(\"start new dispatcher\");\n        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);\n\n        // Make a blocking call to initialize the cache.\n        mCache.initialize();\n\n        Request<?> request;\n        while (true) {\n            // release previous request object to avoid leaking request object when mQueue is drained.\n            request = null;\n            try {\n                // Take a request from the queue.\n                request = mCacheQueue.take();\n            } catch (InterruptedException e) {\n                // We may have been interrupted because it was time to quit.\n                if (mQuit) {\n                    return;\n                }\n                continue;\n            }\n            try {\n                request.addMarker(\"cache-queue-take\");\n\n                // If the request has been canceled, don't bother dispatching it.\n                if (request.isCanceled()) {\n                    request.finish(\"cache-discard-canceled\");\n                    continue;\n                }\n\n                // Attempt to retrieve this item from cache.\n                Cache.Entry entry = mCache.get(request.getCacheKey());\n                if (entry == null) {\n                    request.addMarker(\"cache-miss\");\n                    // Cache miss; send off to the network dispatcher.\n                    mNetworkQueue.put(request);\n                    continue;\n                }\n\n                // If it is completely expired, just send it to the network.\n                if (entry.isExpired()) {\n                    request.addMarker(\"cache-hit-expired\");\n                    request.setCacheEntry(entry);\n                    mNetworkQueue.put(request);\n                    continue;\n                }\n\n                // We have a cache hit; parse its data for delivery back to the request.\n                request.addMarker(\"cache-hit\");\n                Response<?> response = request.parseNetworkResponse(\n                        new NetworkResponse(entry.data, entry.responseHeaders));\n                request.addMarker(\"cache-hit-parsed\");\n\n                if (!entry.refreshNeeded()) {\n                    // Completely unexpired cache hit. Just deliver the response.\n                    mDelivery.postResponse(request, response);\n                } else {\n                    // Soft-expired cache hit. We can deliver the cached response,\n                    // but we need to also send the request to the network for\n                    // refreshing.\n                    request.addMarker(\"cache-hit-refresh-needed\");\n                    request.setCacheEntry(entry);\n\n                    // Mark the response as intermediate.\n                    response.intermediate = true;\n\n                    // Post the intermediate response back to the user and have\n                    // the delivery then forward the request along to the network.\n                    final Request<?> finalRequest = request;\n                    mDelivery.postResponse(request, response, new Runnable() {\n                        @Override\n                        public void run() {\n                            try {\n                                mNetworkQueue.put(finalRequest);\n                            } catch (InterruptedException e) {\n                                // Not much we can do about this.\n                            }\n                        }\n                    });\n                }\n            } catch (Exception e) {\n                VolleyLog.e(e, \"Unhandled exception %s\", e.toString());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/DefaultRetryPolicy.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\n/**\n * Default retry policy for requests.\n */\npublic class DefaultRetryPolicy implements RetryPolicy {\n    /** The current timeout in milliseconds. */\n    private int mCurrentTimeoutMs;\n\n    /** The current retry count. */\n    private int mCurrentRetryCount;\n\n    /** The maximum number of attempts. */\n    private final int mMaxNumRetries;\n\n    /** The backoff multiplier for the policy. */\n    private final float mBackoffMultiplier;\n\n    /** The default socket timeout in milliseconds */\n    public static final int DEFAULT_TIMEOUT_MS = 2500;\n\n    /** The default number of retries */\n    public static final int DEFAULT_MAX_RETRIES = 0;\n\n    /** The default backoff multiplier */\n    public static final float DEFAULT_BACKOFF_MULT = 1f;\n\n\n    /**\n     * Constructs a new retry policy using the default timeouts.\n     */\n    public DefaultRetryPolicy() {\n        this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT);\n    }\n\n    /**\n     * Constructs a new retry policy.\n     * @param initialTimeoutMs The initial timeout for the policy.\n     * @param maxNumRetries The maximum number of retries.\n     * @param backoffMultiplier Backoff multiplier for the policy.\n     */\n    public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) {\n        mCurrentTimeoutMs = initialTimeoutMs;\n        mMaxNumRetries = maxNumRetries;\n        mBackoffMultiplier = backoffMultiplier;\n    }\n\n    /**\n     * Returns the current timeout.\n     */\n    @Override\n    public int getCurrentTimeout() {\n        return mCurrentTimeoutMs;\n    }\n\n    /**\n     * Returns the current retry count.\n     */\n    @Override\n    public int getCurrentRetryCount() {\n        return mCurrentRetryCount;\n    }\n\n    /**\n     * Returns the backoff multiplier for the policy.\n     */\n    public float getBackoffMultiplier() {\n        return mBackoffMultiplier;\n    }\n\n    /**\n     * Prepares for the next retry by applying a backoff to the timeout.\n     * @param error The error code of the last attempt.\n     */\n    @Override\n    public void retry(VolleyError error) throws VolleyError {\n        mCurrentRetryCount++;\n        mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);\n        if (!hasAttemptRemaining()) {\n            throw error;\n        }\n    }\n\n    /**\n     * Returns true if this policy has attempts remaining, false otherwise.\n     */\n    protected boolean hasAttemptRemaining() {\n        return mCurrentRetryCount <= mMaxNumRetries;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/ExecutorDelivery.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\nimport android.os.Handler;\n\nimport java.util.concurrent.Executor;\n\n/**\n * Delivers responses and errors.\n */\npublic class ExecutorDelivery implements ResponseDelivery {\n    /** Used for posting responses, typically to the main thread. */\n    private final Executor mResponsePoster;\n\n    /**\n     * Creates a new response delivery interface.\n     * @param handler {@link Handler} to post responses on\n     */\n    public ExecutorDelivery(final Handler handler) {\n        // Make an Executor that just wraps the handler.\n        mResponsePoster = new Executor() {\n            @Override\n            public void execute(Runnable command) {\n                handler.post(command);\n            }\n        };\n    }\n\n    /**\n     * Creates a new response delivery interface, mockable version\n     * for testing.\n     * @param executor For running delivery tasks\n     */\n    public ExecutorDelivery(Executor executor) {\n        mResponsePoster = executor;\n    }\n\n    @Override\n    public void postResponse(Request<?> request, Response<?> response) {\n        postResponse(request, response, null);\n    }\n\n    @Override\n    public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {\n        request.markDelivered();\n        request.addMarker(\"post-response\");\n        mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));\n    }\n\n    @Override\n    public void postError(Request<?> request, VolleyError error) {\n        request.addMarker(\"post-error\");\n        Response<?> response = Response.error(error);\n        mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));\n    }\n\n    /**\n     * A Runnable used for delivering network responses to a listener on the\n     * main thread.\n     */\n    @SuppressWarnings(\"rawtypes\")\n    private class ResponseDeliveryRunnable implements Runnable {\n        private final Request mRequest;\n        private final Response mResponse;\n        private final Runnable mRunnable;\n\n        public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {\n            mRequest = request;\n            mResponse = response;\n            mRunnable = runnable;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        @Override\n        public void run() {\n            // If this request has canceled, finish it and don't deliver.\n            if (mRequest.isCanceled()) {\n                mRequest.finish(\"canceled-at-delivery\");\n                return;\n            }\n\n            // Deliver a normal response or error, depending.\n            if (mResponse.isSuccess()) {\n                mRequest.deliverResponse(mResponse.result);\n            } else {\n                mRequest.deliverError(mResponse.error);\n            }\n\n            // If this is an intermediate response, add a marker, otherwise we're done\n            // and the request can be finished.\n            if (mResponse.intermediate) {\n                mRequest.addMarker(\"intermediate-response\");\n            } else {\n                mRequest.finish(\"done\");\n            }\n\n            // If we have been provided a post-delivery runnable, run it.\n            if (mRunnable != null) {\n                mRunnable.run();\n            }\n       }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/InternalUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\nimport java.io.UnsupportedEncodingException;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\n/**\n * User: mcxiaoke\n * Date: 15/3/17\n * Time: 14:47\n */\nclass InternalUtils {\n\n    // http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java\n    private final static char[] HEX_CHARS = \"0123456789ABCDEF\".toCharArray();\n\n    private static String convertToHex(byte[] bytes) {\n        char[] hexChars = new char[bytes.length * 2];\n        for (int j = 0; j < bytes.length; j++) {\n            int v = bytes[j] & 0xFF;\n            hexChars[j * 2] = HEX_CHARS[v >>> 4];\n            hexChars[j * 2 + 1] = HEX_CHARS[v & 0x0F];\n        }\n        return new String(hexChars);\n    }\n\n    public static String sha1Hash(String text) {\n        String hash = null;\n        try {\n            final MessageDigest digest = MessageDigest.getInstance(\"SHA-1\");\n            final byte[] bytes = text.getBytes(\"UTF-8\");\n            digest.update(bytes, 0, bytes.length);\n            hash = convertToHex(digest.digest());\n        } catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n        return hash;\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/Network.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\n/**\n * An interface for performing requests.\n */\npublic interface Network {\n    /**\n     * Performs the specified request.\n     * @param request Request to process\n     * @return A {@link NetworkResponse} with data and caching metadata; will never be null\n     * @throws VolleyError on errors\n     */\n    public NetworkResponse performRequest(Request<?> request) throws VolleyError;\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/NetworkDispatcher.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\nimport android.annotation.TargetApi;\nimport android.net.TrafficStats;\nimport android.os.Build;\nimport android.os.Process;\nimport android.os.SystemClock;\n\nimport java.util.concurrent.BlockingQueue;\n\n/**\n * Provides a thread for performing network dispatch from a queue of requests.\n *\n * Requests added to the specified queue are processed from the network via a\n * specified {@link Network} interface. Responses are committed to cache, if\n * eligible, using a specified {@link Cache} interface. Valid responses and\n * errors are posted back to the caller via a {@link ResponseDelivery}.\n */\npublic class NetworkDispatcher extends Thread {\n    /** The queue of requests to service. */\n    private final BlockingQueue<Request<?>> mQueue;\n    /** The network interface for processing requests. */\n    private final Network mNetwork;\n    /** The cache to write to. */\n    private final Cache mCache;\n    /** For posting responses and errors. */\n    private final ResponseDelivery mDelivery;\n    /** Used for telling us to die. */\n    private volatile boolean mQuit = false;\n\n    /**\n     * Creates a new network dispatcher thread.  You must call {@link #start()}\n     * in order to begin processing.\n     *\n     * @param queue Queue of incoming requests for triage\n     * @param network Network interface to use for performing requests\n     * @param cache Cache interface to use for writing responses to cache\n     * @param delivery Delivery interface to use for posting responses\n     */\n    public NetworkDispatcher(BlockingQueue<Request<?>> queue,\n            Network network, Cache cache,\n            ResponseDelivery delivery) {\n        mQueue = queue;\n        mNetwork = network;\n        mCache = cache;\n        mDelivery = delivery;\n    }\n\n    /**\n     * Forces this dispatcher to quit immediately.  If any requests are still in\n     * the queue, they are not guaranteed to be processed.\n     */\n    public void quit() {\n        mQuit = true;\n        interrupt();\n    }\n\n    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)\n    private void addTrafficStatsTag(Request<?> request) {\n        // Tag the request (if API >= 14)\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {\n            TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());\n        }\n    }\n\n    @Override\n    public void run() {\n        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);\n        Request<?> request;\n        while (true) {\n            long startTimeMs = SystemClock.elapsedRealtime();\n            // release previous request object to avoid leaking request object when mQueue is drained.\n            request = null;\n            try {\n                // Take a request from the queue.\n                request = mQueue.take();\n            } catch (InterruptedException e) {\n                // We may have been interrupted because it was time to quit.\n                if (mQuit) {\n                    return;\n                }\n                continue;\n            }\n\n            try {\n                request.addMarker(\"network-queue-take\");\n\n                // If the request was cancelled already, do not perform the\n                // network request.\n                if (request.isCanceled()) {\n                    request.finish(\"network-discard-cancelled\");\n                    continue;\n                }\n\n                addTrafficStatsTag(request);\n\n                // Perform the network request.\n                NetworkResponse networkResponse = mNetwork.performRequest(request);\n                request.addMarker(\"network-http-complete\");\n\n                // If the server returned 304 AND we delivered a response already,\n                // we're done -- don't deliver a second identical response.\n                if (networkResponse.notModified && request.hasHadResponseDelivered()) {\n                    request.finish(\"not-modified\");\n                    continue;\n                }\n\n                // Parse the response here on the worker thread.\n                Response<?> response = request.parseNetworkResponse(networkResponse);\n                request.addMarker(\"network-parse-complete\");\n\n                // Write to cache if applicable.\n                // TODO: Only update cache metadata instead of entire record for 304s.\n                if (request.shouldCache() && response.cacheEntry != null) {\n                    mCache.put(request.getCacheKey(), response.cacheEntry);\n                    request.addMarker(\"network-cache-written\");\n                }\n\n                // Post the response back.\n                request.markDelivered();\n                mDelivery.postResponse(request, response);\n            } catch (VolleyError volleyError) {\n                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);\n                parseAndDeliverNetworkError(request, volleyError);\n            } catch (Exception e) {\n                VolleyLog.e(e, \"Unhandled exception %s\", e.toString());\n                VolleyError volleyError = new VolleyError(e);\n                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);\n                mDelivery.postError(request, volleyError);\n            }\n        }\n    }\n\n    private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {\n        error = request.parseNetworkError(error);\n        mDelivery.postError(request, error);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/NetworkError.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\n/**\n * Indicates that there was a network error when performing a Volley request.\n */\n@SuppressWarnings(\"serial\")\npublic class NetworkError extends VolleyError {\n    public NetworkError() {\n        super();\n    }\n\n    public NetworkError(Throwable cause) {\n        super(cause);\n    }\n\n    public NetworkError(NetworkResponse networkResponse) {\n        super(networkResponse);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/NetworkResponse.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\nimport org.apache.http.HttpStatus;\n\nimport java.io.Serializable;\nimport java.util.Collections;\nimport java.util.Map;\n\n/**\n * Data and headers returned from {@link Network#performRequest(Request)}.\n */\npublic class NetworkResponse implements Serializable {\n    private static final long serialVersionUID = -20150728102000L;\n\n    /**\n     * Creates a new network response.\n     * @param statusCode the HTTP status code\n     * @param data Response body\n     * @param headers Headers returned with this response, or null for none\n     * @param notModified True if the server returned a 304 and the data was already in cache\n     * @param networkTimeMs Round-trip network time to receive network response\n     */\n    public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,\n            boolean notModified, long networkTimeMs) {\n        this.statusCode = statusCode;\n        this.data = data;\n        this.headers = headers;\n        this.notModified = notModified;\n        this.networkTimeMs = networkTimeMs;\n    }\n\n    public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,\n            boolean notModified) {\n        this(statusCode, data, headers, notModified, 0);\n    }\n\n    public NetworkResponse(byte[] data) {\n        this(HttpStatus.SC_OK, data, Collections.<String, String>emptyMap(), false, 0);\n    }\n\n    public NetworkResponse(byte[] data, Map<String, String> headers) {\n        this(HttpStatus.SC_OK, data, headers, false, 0);\n    }\n\n    /** The HTTP status code. */\n    public final int statusCode;\n\n    /** Raw data from this response. */\n    public final byte[] data;\n\n    /** Response headers. */\n    public final Map<String, String> headers;\n\n    /** True if the server returned a 304 (Not Modified). */\n    public final boolean notModified;\n\n    /** Network roundtrip time in milliseconds. */\n    public final long networkTimeMs;\n}\n\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/NoConnectionError.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\n/**\n * Error indicating that no connection could be established when performing a Volley request.\n */\n@SuppressWarnings(\"serial\")\npublic class NoConnectionError extends NetworkError {\n    public NoConnectionError() {\n        super();\n    }\n\n    public NoConnectionError(Throwable reason) {\n        super(reason);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/ParseError.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\n/**\n * Indicates that the server's response could not be parsed.\n */\n@SuppressWarnings(\"serial\")\npublic class ParseError extends VolleyError {\n    public ParseError() { }\n\n    public ParseError(NetworkResponse networkResponse) {\n        super(networkResponse);\n    }\n\n    public ParseError(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/RedirectError.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\n/**\n * Indicates that there was a redirection.\n */\npublic class RedirectError extends VolleyError {\n\n    public RedirectError() {\n    }\n\n    public RedirectError(final Throwable cause) {\n        super(cause);\n    }\n\n    public RedirectError(final NetworkResponse response) {\n        super(response);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/Request.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\nimport android.net.TrafficStats;\nimport android.net.Uri;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyLog.MarkerLog;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLEncoder;\nimport java.util.Collections;\nimport java.util.Map;\n\n/**\n * Base class for all network requests.\n *\n * @param <T> The type of parsed response this request expects.\n */\npublic abstract class Request<T> implements Comparable<Request<T>> {\n\n    /**\n     * Default encoding for POST or PUT parameters. See {@link #getParamsEncoding()}.\n     */\n    private static final String DEFAULT_PARAMS_ENCODING = \"UTF-8\";\n\n    /**\n     * Supported request methods.\n     */\n    public interface Method {\n        int DEPRECATED_GET_OR_POST = -1;\n        int GET = 0;\n        int POST = 1;\n        int PUT = 2;\n        int DELETE = 3;\n        int HEAD = 4;\n        int OPTIONS = 5;\n        int TRACE = 6;\n        int PATCH = 7;\n    }\n\n    /** An event log tracing the lifetime of this request; for debugging. */\n    private final MarkerLog mEventLog = MarkerLog.ENABLED ? new MarkerLog() : null;\n\n    /**\n     * Request method of this request.  Currently supports GET, POST, PUT, DELETE, HEAD, OPTIONS,\n     * TRACE, and PATCH.\n     */\n    private final int mMethod;\n\n    /** URL of this request. */\n    private final String mUrl;\n\n    /** The redirect url to use for 3xx http responses */\n    private String mRedirectUrl;\n\n    /** The unique identifier of the request */\n    private String mIdentifier;\n\n    /** Default tag for {@link TrafficStats}. */\n    private final int mDefaultTrafficStatsTag;\n\n    /** Listener interface for errors. */\n    private Response.ErrorListener mErrorListener;\n\n    /** Sequence number of this request, used to enforce FIFO ordering. */\n    private Integer mSequence;\n\n    /** The request queue this request is associated with. */\n    private RequestQueue mRequestQueue;\n\n    /** Whether or not responses to this request should be cached. */\n    private boolean mShouldCache = true;\n\n    /** Whether or not this request has been canceled. */\n    private boolean mCanceled = false;\n\n    /** Whether or not a response has been delivered for this request yet. */\n    private boolean mResponseDelivered = false;\n\n    /** The retry policy for this request. */\n    private RetryPolicy mRetryPolicy;\n\n    /**\n     * When a request can be retrieved from cache but must be refreshed from\n     * the network, the cache entry will be stored here so that in the event of\n     * a \"Not Modified\" response, we can be sure it hasn't been evicted from cache.\n     */\n    private Cache.Entry mCacheEntry = null;\n\n    /** An opaque token tagging this request; used for bulk cancellation. */\n    private Object mTag;\n\n    /**\n     * Creates a new request with the given URL and error listener.  Note that\n     * the normal response listener is not provided here as delivery of responses\n     * is provided by subclasses, who have a better idea of how to deliver an\n     * already-parsed response.\n     *\n     * @deprecated Use {@link #Request(int, String, Response.ErrorListener)}.\n     */\n    @Deprecated\n    public Request(String url, Response.ErrorListener listener) {\n        this(Method.DEPRECATED_GET_OR_POST, url, listener);\n    }\n\n    /**\n     * Creates a new request with the given method (one of the values from {@link Method}),\n     * URL, and error listener.  Note that the normal response listener is not provided here as\n     * delivery of responses is provided by subclasses, who have a better idea of how to deliver\n     * an already-parsed response.\n     */\n    public Request(int method, String url, Response.ErrorListener listener) {\n        mMethod = method;\n        mUrl = url;\n        mIdentifier = createIdentifier(method, url);\n        mErrorListener = listener;\n        setRetryPolicy(new DefaultRetryPolicy());\n\n        mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url);\n    }\n\n    /**\n     * Return the method for this request.  Can be one of the values in {@link Method}.\n     */\n    public int getMethod() {\n        return mMethod;\n    }\n\n    /**\n     * Set a tag on this request. Can be used to cancel all requests with this\n     * tag by {@link RequestQueue#cancelAll(Object)}.\n     *\n     * @return This Request object to allow for chaining.\n     */\n    public Request<?> setTag(Object tag) {\n        mTag = tag;\n        return this;\n    }\n\n    /**\n     * Returns this request's tag.\n     * @see Request#setTag(Object)\n     */\n    public Object getTag() {\n        return mTag;\n    }\n\n    /**\n     * @return this request's {@link Response.ErrorListener}.\n     */\n    public Response.ErrorListener getErrorListener() {\n        return mErrorListener;\n    }\n\n    /**\n     * @return A tag for use with {@link TrafficStats#setThreadStatsTag(int)}\n     */\n    public int getTrafficStatsTag() {\n        return mDefaultTrafficStatsTag;\n    }\n\n    /**\n     * @return The hashcode of the URL's host component, or 0 if there is none.\n     */\n    private static int findDefaultTrafficStatsTag(String url) {\n        if (!TextUtils.isEmpty(url)) {\n            Uri uri = Uri.parse(url);\n            if (uri != null) {\n                String host = uri.getHost();\n                if (host != null) {\n                    return host.hashCode();\n                }\n            }\n        }\n        return 0;\n    }\n\n    /**\n     * Sets the retry policy for this request.\n     *\n     * @return This Request object to allow for chaining.\n     */\n    public Request<?> setRetryPolicy(RetryPolicy retryPolicy) {\n        mRetryPolicy = retryPolicy;\n        return this;\n    }\n\n    /**\n     * Adds an event to this request's event log; for debugging.\n     */\n    public void addMarker(String tag) {\n        if (MarkerLog.ENABLED) {\n            mEventLog.add(tag, Thread.currentThread().getId());\n        }\n    }\n\n    /**\n     * Notifies the request queue that this request has finished (successfully or with error).\n     *\n     * <p>Also dumps all events from this request's event log; for debugging.</p>\n     */\n    void finish(final String tag) {\n        if (mRequestQueue != null) {\n            mRequestQueue.finish(this);\n            onFinish();\n        }\n        if (MarkerLog.ENABLED) {\n            final long threadId = Thread.currentThread().getId();\n            if (Looper.myLooper() != Looper.getMainLooper()) {\n                // If we finish marking off of the main thread, we need to\n                // actually do it on the main thread to ensure correct ordering.\n                Handler mainThread = new Handler(Looper.getMainLooper());\n                mainThread.post(new Runnable() {\n                    @Override\n                    public void run() {\n                        mEventLog.add(tag, threadId);\n                        mEventLog.finish(this.toString());\n                    }\n                });\n                return;\n            }\n\n            mEventLog.add(tag, threadId);\n            mEventLog.finish(this.toString());\n        }\n    }\n\n    /**\n     * clear listeners when finished\n     */\n    protected void onFinish() {\n        mErrorListener = null;\n    }\n\n    /**\n     * Associates this request with the given queue. The request queue will be notified when this\n     * request has finished.\n     *\n     * @return This Request object to allow for chaining.\n     */\n    public Request<?> setRequestQueue(RequestQueue requestQueue) {\n        mRequestQueue = requestQueue;\n        return this;\n    }\n\n    /**\n     * Sets the sequence number of this request.  Used by {@link RequestQueue}.\n     *\n     * @return This Request object to allow for chaining.\n     */\n    public final Request<?> setSequence(int sequence) {\n        mSequence = sequence;\n        return this;\n    }\n\n    /**\n     * Returns the sequence number of this request.\n     */\n    public final int getSequence() {\n        if (mSequence == null) {\n            throw new IllegalStateException(\"getSequence called before setSequence\");\n        }\n        return mSequence;\n    }\n\n    /**\n     * Returns the URL of this request.\n     */\n    public String getUrl() {\n        return (mRedirectUrl != null) ? mRedirectUrl : mUrl;\n    }\n\n    /**\n     * Returns the URL of the request before any redirects have occurred.\n     */\n    public String getOriginUrl() {\n    \treturn mUrl;\n    }\n\n    /**\n     * Returns the identifier of the request.\n     */\n    public String getIdentifier() {\n        return mIdentifier;\n    }\n\n    /**\n     * Sets the redirect url to handle 3xx http responses.\n     */\n    public void setRedirectUrl(String redirectUrl) {\n    \tmRedirectUrl = redirectUrl;\n    }\n\n    /**\n     * Returns the cache key for this request.  By default, this is the URL.\n     */\n    public String getCacheKey() {\n        return mMethod + \":\" + mUrl;\n    }\n\n    /**\n     * Annotates this request with an entry retrieved for it from cache.\n     * Used for cache coherency support.\n     *\n     * @return This Request object to allow for chaining.\n     */\n    public Request<?> setCacheEntry(Cache.Entry entry) {\n        mCacheEntry = entry;\n        return this;\n    }\n\n    /**\n     * Returns the annotated cache entry, or null if there isn't one.\n     */\n    public Cache.Entry getCacheEntry() {\n        return mCacheEntry;\n    }\n\n    /**\n     * Mark this request as canceled.  No callback will be delivered.\n     */\n    public void cancel() {\n        mCanceled = true;\n    }\n\n    /**\n     * Returns true if this request has been canceled.\n     */\n    public boolean isCanceled() {\n        return mCanceled;\n    }\n\n    /**\n     * Returns a list of extra HTTP headers to go along with this request. Can\n     * throw {@link AuthFailureError} as authentication may be required to\n     * provide these values.\n     * @throws AuthFailureError In the event of auth failure\n     */\n    public Map<String, String> getHeaders() throws AuthFailureError {\n        return Collections.emptyMap();\n    }\n\n    /**\n     * Returns a Map of POST parameters to be used for this request, or null if\n     * a simple GET should be used.  Can throw {@link AuthFailureError} as\n     * authentication may be required to provide these values.\n     *\n     * <p>Note that only one of getPostParams() and getPostBody() can return a non-null\n     * value.</p>\n     * @throws AuthFailureError In the event of auth failure\n     *\n     * @deprecated Use {@link #getParams()} instead.\n     */\n    @Deprecated\n    protected Map<String, String> getPostParams() throws AuthFailureError {\n        return getParams();\n    }\n\n    /**\n     * Returns which encoding should be used when converting POST parameters returned by\n     * {@link #getPostParams()} into a raw POST body.\n     *\n     * <p>This controls both encodings:\n     * <ol>\n     *     <li>The string encoding used when converting parameter names and values into bytes prior\n     *         to URL encoding them.</li>\n     *     <li>The string encoding used when converting the URL encoded parameters into a raw\n     *         byte array.</li>\n     * </ol>\n     *\n     * @deprecated Use {@link #getParamsEncoding()} instead.\n     */\n    @Deprecated\n    protected String getPostParamsEncoding() {\n        return getParamsEncoding();\n    }\n\n    /**\n     * @deprecated Use {@link #getBodyContentType()} instead.\n     */\n    @Deprecated\n    public String getPostBodyContentType() {\n        return getBodyContentType();\n    }\n\n    /**\n     * Returns the raw POST body to be sent.\n     *\n     * @throws AuthFailureError In the event of auth failure\n     *\n     * @deprecated Use {@link #getBody()} instead.\n     */\n    @Deprecated\n    public byte[] getPostBody() throws AuthFailureError {\n        // Note: For compatibility with legacy clients of volley, this implementation must remain\n        // here instead of simply calling the getBody() function because this function must\n        // call getPostParams() and getPostParamsEncoding() since legacy clients would have\n        // overridden these two member functions for POST requests.\n        Map<String, String> postParams = getPostParams();\n        if (postParams != null && postParams.size() > 0) {\n            return encodeParameters(postParams, getPostParamsEncoding());\n        }\n        return null;\n    }\n\n    /**\n     * Returns a Map of parameters to be used for a POST or PUT request.  Can throw\n     * {@link AuthFailureError} as authentication may be required to provide these values.\n     *\n     * <p>Note that you can directly override {@link #getBody()} for custom data.</p>\n     *\n     * @throws AuthFailureError in the event of auth failure\n     */\n    protected Map<String, String> getParams() throws AuthFailureError {\n        return null;\n    }\n\n    /**\n     * Returns which encoding should be used when converting POST or PUT parameters returned by\n     * {@link #getParams()} into a raw POST or PUT body.\n     *\n     * <p>This controls both encodings:\n     * <ol>\n     *     <li>The string encoding used when converting parameter names and values into bytes prior\n     *         to URL encoding them.</li>\n     *     <li>The string encoding used when converting the URL encoded parameters into a raw\n     *         byte array.</li>\n     * </ol>\n     */\n    protected String getParamsEncoding() {\n        return DEFAULT_PARAMS_ENCODING;\n    }\n\n    /**\n     * Returns the content type of the POST or PUT body.\n     */\n    public String getBodyContentType() {\n        return \"application/x-www-form-urlencoded; charset=\" + getParamsEncoding();\n    }\n\n    /**\n     * Returns the raw POST or PUT body to be sent.\n     *\n     * <p>By default, the body consists of the request parameters in\n     * application/x-www-form-urlencoded format. When overriding this method, consider overriding\n     * {@link #getBodyContentType()} as well to match the new body format.\n     *\n     * @throws AuthFailureError in the event of auth failure\n     */\n    public byte[] getBody() throws AuthFailureError {\n        Map<String, String> params = getParams();\n        if (params != null && params.size() > 0) {\n            return encodeParameters(params, getParamsEncoding());\n        }\n        return null;\n    }\n\n    /**\n     * Converts <code>params</code> into an application/x-www-form-urlencoded encoded string.\n     */\n    private byte[] encodeParameters(Map<String, String> params, String paramsEncoding) {\n        StringBuilder encodedParams = new StringBuilder();\n        try {\n            for (Map.Entry<String, String> entry : params.entrySet()) {\n                encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));\n                encodedParams.append('=');\n                encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding));\n                encodedParams.append('&');\n            }\n            return encodedParams.toString().getBytes(paramsEncoding);\n        } catch (UnsupportedEncodingException uee) {\n            throw new RuntimeException(\"Encoding not supported: \" + paramsEncoding, uee);\n        }\n    }\n\n    /**\n     * Set whether or not responses to this request should be cached.\n     *\n     * @return This Request object to allow for chaining.\n     */\n    public final Request<?> setShouldCache(boolean shouldCache) {\n        mShouldCache = shouldCache;\n        return this;\n    }\n\n    /**\n     * Returns true if responses to this request should be cached.\n     */\n    public final boolean shouldCache() {\n        return mShouldCache;\n    }\n\n    /**\n     * Priority values.  Requests will be processed from higher priorities to\n     * lower priorities, in FIFO order.\n     */\n    public enum Priority {\n        LOW,\n        NORMAL,\n        HIGH,\n        IMMEDIATE\n    }\n\n    /**\n     * Returns the {@link Priority} of this request; {@link Priority#NORMAL} by default.\n     */\n    public Priority getPriority() {\n        return Priority.NORMAL;\n    }\n\n    /**\n     * Returns the socket timeout in milliseconds per retry attempt. (This value can be changed\n     * per retry attempt if a backoff is specified via backoffTimeout()). If there are no retry\n     * attempts remaining, this will cause delivery of a {@link TimeoutError} error.\n     */\n    public final int getTimeoutMs() {\n        return mRetryPolicy.getCurrentTimeout();\n    }\n\n    /**\n     * Returns the retry policy that should be used  for this request.\n     */\n    public RetryPolicy getRetryPolicy() {\n        return mRetryPolicy;\n    }\n\n    /**\n     * Mark this request as having a response delivered on it.  This can be used\n     * later in the request's lifetime for suppressing identical responses.\n     */\n    public void markDelivered() {\n        mResponseDelivered = true;\n    }\n\n    /**\n     * Returns true if this request has had a response delivered for it.\n     */\n    public boolean hasHadResponseDelivered() {\n        return mResponseDelivered;\n    }\n\n    /**\n     * Subclasses must implement this to parse the raw network response\n     * and return an appropriate response type. This method will be\n     * called from a worker thread.  The response will not be delivered\n     * if you return null.\n     * @param response Response from the network\n     * @return The parsed response, or null in the case of an error\n     */\n    abstract protected Response<T> parseNetworkResponse(NetworkResponse response);\n\n    /**\n     * Subclasses can override this method to parse 'networkError' and return a more specific error.\n     *\n     * <p>The default implementation just returns the passed 'networkError'.</p>\n     *\n     * @param volleyError the error retrieved from the network\n     * @return an NetworkError augmented with additional information\n     */\n    protected VolleyError parseNetworkError(VolleyError volleyError) {\n        return volleyError;\n    }\n\n    /**\n     * Subclasses must implement this to perform delivery of the parsed\n     * response to their listeners.  The given response is guaranteed to\n     * be non-null; responses that fail to parse are not delivered.\n     * @param response The parsed response returned by\n     * {@link #parseNetworkResponse(NetworkResponse)}\n     */\n    abstract protected void deliverResponse(T response);\n\n    /**\n     * Delivers error message to the ErrorListener that the Request was\n     * initialized with.\n     *\n     * @param error Error details\n     */\n    public void deliverError(VolleyError error) {\n        if (mErrorListener != null) {\n            mErrorListener.onErrorResponse(error);\n        }\n    }\n\n    /**\n     * Our comparator sorts from high to low priority, and secondarily by\n     * sequence number to provide FIFO ordering.\n     */\n    @Override\n    public int compareTo(Request<T> other) {\n        Priority left = this.getPriority();\n        Priority right = other.getPriority();\n\n        // High-priority requests are \"lesser\" so they are sorted to the front.\n        // Equal priorities are sorted by sequence number to provide FIFO ordering.\n        return left == right ?\n                this.mSequence - other.mSequence :\n                right.ordinal() - left.ordinal();\n    }\n\n    @Override\n    public String toString() {\n        String trafficStatsTag = \"0x\" + Integer.toHexString(getTrafficStatsTag());\n        return (mCanceled ? \"[X] \" : \"[ ] \") + getUrl() + \" \" + trafficStatsTag + \" \"\n                + getPriority() + \" \" + mSequence;\n    }\n\n    private static long sCounter;\n    /**\n     *  sha1(Request:method:url:timestamp:counter)\n     * @param method http method\n     * @param url               http request url\n     * @return sha1 hash string\n     */\n    private static String createIdentifier(final int method, final String url) {\n        return InternalUtils.sha1Hash(\"Request:\" + method + \":\" + url +\n                \":\" + System.currentTimeMillis() + \":\" + (sCounter++));\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/RequestQueue.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\nimport android.os.Handler;\nimport android.os.Looper;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Queue;\nimport java.util.Set;\nimport java.util.concurrent.PriorityBlockingQueue;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * A request dispatch queue with a thread pool of dispatchers.\n *\n * Calling {@link #add(Request)} will enqueue the given Request for dispatch,\n * resolving from either cache or network on a worker thread, and then delivering\n * a parsed response on the main thread.\n */\npublic class RequestQueue {\n\n    /** Callback interface for completed requests. */\n    public static interface RequestFinishedListener<T> {\n        /** Called when a request has finished processing. */\n        public void onRequestFinished(Request<T> request);\n    }\n\n    /** Used for generating monotonically-increasing sequence numbers for requests. */\n    private AtomicInteger mSequenceGenerator = new AtomicInteger();\n\n    /**\n     * Staging area for requests that already have a duplicate request in flight.\n     *\n     * <ul>\n     *     <li>containsKey(cacheKey) indicates that there is a request in flight for the given cache\n     *          key.</li>\n     *     <li>get(cacheKey) returns waiting requests for the given cache key. The in flight request\n     *          is <em>not</em> contained in that list. Is null if no requests are staged.</li>\n     * </ul>\n     */\n    private final Map<String, Queue<Request<?>>> mWaitingRequests =\n            new HashMap<String, Queue<Request<?>>>();\n\n    /**\n     * The set of all requests currently being processed by this RequestQueue. A Request\n     * will be in this set if it is waiting in any queue or currently being processed by\n     * any dispatcher.\n     */\n    private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();\n\n    /** The cache triage queue. */\n    private final PriorityBlockingQueue<Request<?>> mCacheQueue =\n        new PriorityBlockingQueue<Request<?>>();\n\n    /** The queue of requests that are actually going out to the network. */\n    private final PriorityBlockingQueue<Request<?>> mNetworkQueue =\n        new PriorityBlockingQueue<Request<?>>();\n\n    /** Number of network request dispatcher threads to start. */\n    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;\n\n    /** Cache interface for retrieving and storing responses. */\n    private final Cache mCache;\n\n    /** Network interface for performing requests. */\n    private final Network mNetwork;\n\n    /** Response delivery mechanism. */\n    private final ResponseDelivery mDelivery;\n\n    /** The network dispatchers. */\n    private NetworkDispatcher[] mDispatchers;\n\n    /** The cache dispatcher. */\n    private CacheDispatcher mCacheDispatcher;\n\n    private List<RequestFinishedListener> mFinishedListeners =\n            new ArrayList<RequestFinishedListener>();\n\n    /**\n     * Creates the worker pool. Processing will not begin until {@link #start()} is called.\n     *\n     * @param cache A Cache to use for persisting responses to disk\n     * @param network A Network interface for performing HTTP requests\n     * @param threadPoolSize Number of network dispatcher threads to create\n     * @param delivery A ResponseDelivery interface for posting responses and errors\n     */\n    public RequestQueue(Cache cache, Network network, int threadPoolSize,\n            ResponseDelivery delivery) {\n        mCache = cache;\n        mNetwork = network;\n        mDispatchers = new NetworkDispatcher[threadPoolSize];\n        mDelivery = delivery;\n    }\n\n    /**\n     * Creates the worker pool. Processing will not begin until {@link #start()} is called.\n     *\n     * @param cache A Cache to use for persisting responses to disk\n     * @param network A Network interface for performing HTTP requests\n     * @param threadPoolSize Number of network dispatcher threads to create\n     */\n    public RequestQueue(Cache cache, Network network, int threadPoolSize) {\n        this(cache, network, threadPoolSize,\n                new ExecutorDelivery(new Handler(Looper.getMainLooper())));\n    }\n\n    /**\n     * Creates the worker pool. Processing will not begin until {@link #start()} is called.\n     *\n     * @param cache A Cache to use for persisting responses to disk\n     * @param network A Network interface for performing HTTP requests\n     */\n    public RequestQueue(Cache cache, Network network) {\n        this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);\n    }\n\n    /**\n     * Starts the dispatchers in this queue.\n     */\n    public void start() {\n        stop();  // Make sure any currently running dispatchers are stopped.\n        // Create the cache dispatcher and start it.\n        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);\n        mCacheDispatcher.start();\n\n        // Create network dispatchers (and corresponding threads) up to the pool size.\n        for (int i = 0; i < mDispatchers.length; i++) {\n            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,\n                    mCache, mDelivery);\n            mDispatchers[i] = networkDispatcher;\n            networkDispatcher.start();\n        }\n    }\n\n    /**\n     * Stops the cache and network dispatchers.\n     */\n    public void stop() {\n        if (mCacheDispatcher != null) {\n            mCacheDispatcher.quit();\n        }\n        for (int i = 0; i < mDispatchers.length; i++) {\n            if (mDispatchers[i] != null) {\n                mDispatchers[i].quit();\n            }\n        }\n    }\n\n    /**\n     * Gets a sequence number.\n     */\n    public int getSequenceNumber() {\n        return mSequenceGenerator.incrementAndGet();\n    }\n\n    /**\n     * Gets the {@link Cache} instance being used.\n     */\n    public Cache getCache() {\n        return mCache;\n    }\n\n    /**\n     * A simple predicate or filter interface for Requests, for use by\n     * {@link RequestQueue#cancelAll(RequestFilter)}.\n     */\n    public interface RequestFilter {\n        public boolean apply(Request<?> request);\n    }\n\n    /**\n     * Cancels all requests in this queue for which the given filter applies.\n     * @param filter The filtering function to use\n     */\n    public void cancelAll(RequestFilter filter) {\n        synchronized (mCurrentRequests) {\n            for (Request<?> request : mCurrentRequests) {\n                if (filter.apply(request)) {\n                    request.cancel();\n                }\n            }\n        }\n    }\n\n    /**\n     * Cancels all requests in this queue with the given tag. Tag must be non-null\n     * and equality is by identity.\n     */\n    public void cancelAll(final Object tag) {\n        if (tag == null) {\n            throw new IllegalArgumentException(\"Cannot cancelAll with a null tag\");\n        }\n        cancelAll(new RequestFilter() {\n            @Override\n            public boolean apply(Request<?> request) {\n                return request.getTag() == tag;\n            }\n        });\n    }\n\n    /**\n     * Adds a Request to the dispatch queue.\n     * @param request The request to service\n     * @return The passed-in request\n     */\n    public <T> Request<T> add(Request<T> request) {\n        // Tag the request as belonging to this queue and add it to the set of current requests.\n        request.setRequestQueue(this);\n        synchronized (mCurrentRequests) {\n            mCurrentRequests.add(request);\n        }\n\n        // Process requests in the order they are added.\n        request.setSequence(getSequenceNumber());\n        request.addMarker(\"add-to-queue\");\n\n        // If the request is uncacheable, skip the cache queue and go straight to the network.\n        if (!request.shouldCache()) {\n            mNetworkQueue.add(request);\n            return request;\n        }\n\n        // Insert request into stage if there's already a request with the same cache key in flight.\n        synchronized (mWaitingRequests) {\n            String cacheKey = request.getCacheKey();\n            if (mWaitingRequests.containsKey(cacheKey)) {\n                // There is already a request in flight. Queue up.\n                Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);\n                if (stagedRequests == null) {\n                    stagedRequests = new LinkedList<Request<?>>();\n                }\n                stagedRequests.add(request);\n                mWaitingRequests.put(cacheKey, stagedRequests);\n                if (VolleyLog.DEBUG) {\n                    VolleyLog.v(\"Request for cacheKey=%s is in flight, putting on hold.\", cacheKey);\n                }\n            } else {\n                // Insert 'null' queue for this cacheKey, indicating there is now a request in\n                // flight.\n                mWaitingRequests.put(cacheKey, null);\n                mCacheQueue.add(request);\n            }\n            return request;\n        }\n    }\n\n    /**\n     * Called from {@link Request#finish(String)}, indicating that processing of the given request\n     * has finished.\n     *\n     * <p>Releases waiting requests for <code>request.getCacheKey()</code> if\n     *      <code>request.shouldCache()</code>.</p>\n     */\n    <T> void finish(Request<T> request) {\n        // Remove from the set of requests currently being processed.\n        synchronized (mCurrentRequests) {\n            mCurrentRequests.remove(request);\n        }\n        synchronized (mFinishedListeners) {\n          for (RequestFinishedListener<T> listener : mFinishedListeners) {\n            listener.onRequestFinished(request);\n          }\n        }\n\n        if (request.shouldCache()) {\n            synchronized (mWaitingRequests) {\n                String cacheKey = request.getCacheKey();\n                Queue<Request<?>> waitingRequests = mWaitingRequests.remove(cacheKey);\n                if (waitingRequests != null) {\n                    if (VolleyLog.DEBUG) {\n                        VolleyLog.v(\"Releasing %d waiting requests for cacheKey=%s.\",\n                                waitingRequests.size(), cacheKey);\n                    }\n                    // Process all queued up requests. They won't be considered as in flight, but\n                    // that's not a problem as the cache has been primed by 'request'.\n                    mCacheQueue.addAll(waitingRequests);\n                }\n            }\n        }\n    }\n\n    public  <T> void addRequestFinishedListener(RequestFinishedListener<T> listener) {\n      synchronized (mFinishedListeners) {\n        mFinishedListeners.add(listener);\n      }\n    }\n\n    /**\n     * Remove a RequestFinishedListener. Has no effect if listener was not previously added.\n     */\n    public  <T> void removeRequestFinishedListener(RequestFinishedListener<T> listener) {\n      synchronized (mFinishedListeners) {\n        mFinishedListeners.remove(listener);\n      }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/Response.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\n/**\n * Encapsulates a parsed response for delivery.\n *\n * @param <T> Parsed type of this response\n */\npublic class Response<T> {\n\n    /** Callback interface for delivering parsed responses. */\n    public interface Listener<T> {\n        /** Called when a response is received. */\n        public void onResponse(T response);\n    }\n\n    /** Callback interface for delivering error responses. */\n    public interface ErrorListener {\n        /**\n         * Callback method that an error has been occurred with the\n         * provided error code and optional user-readable message.\n         */\n        public void onErrorResponse(VolleyError error);\n    }\n\n    /** Returns a successful response containing the parsed result. */\n    public static <T> Response<T> success(T result, Cache.Entry cacheEntry) {\n        return new Response<T>(result, cacheEntry);\n    }\n\n    /**\n     * Returns a failed response containing the given error code and an optional\n     * localized message displayed to the user.\n     */\n    public static <T> Response<T> error(VolleyError error) {\n        return new Response<T>(error);\n    }\n\n    /** Parsed response, or null in the case of error. */\n    public final T result;\n\n    /** Cache metadata for this response, or null in the case of error. */\n    public final Cache.Entry cacheEntry;\n\n    /** Detailed error information if <code>errorCode != OK</code>. */\n    public final VolleyError error;\n\n    /** True if this response was a soft-expired one and a second one MAY be coming. */\n    public boolean intermediate = false;\n\n    /**\n     * Returns whether this response is considered successful.\n     */\n    public boolean isSuccess() {\n        return error == null;\n    }\n\n\n    private Response(T result, Cache.Entry cacheEntry) {\n        this.result = result;\n        this.cacheEntry = cacheEntry;\n        this.error = null;\n    }\n\n    private Response(VolleyError error) {\n        this.result = null;\n        this.cacheEntry = null;\n        this.error = error;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/ResponseDelivery.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\npublic interface ResponseDelivery {\n    /**\n     * Parses a response from the network or cache and delivers it.\n     */\n    public void postResponse(Request<?> request, Response<?> response);\n\n    /**\n     * Parses a response from the network or cache and delivers it. The provided\n     * Runnable will be executed after delivery.\n     */\n    public void postResponse(Request<?> request, Response<?> response, Runnable runnable);\n\n    /**\n     * Posts an error for the given request.\n     */\n    public void postError(Request<?> request, VolleyError error);\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/RetryPolicy.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\n/**\n * Retry policy for a request.\n */\npublic interface RetryPolicy {\n\n    /**\n     * Returns the current timeout (used for logging).\n     */\n    public int getCurrentTimeout();\n\n    /**\n     * Returns the current retry count (used for logging).\n     */\n    public int getCurrentRetryCount();\n\n    /**\n     * Prepares for the next retry by applying a backoff to the timeout.\n     * @param error The error code of the last attempt.\n     * @throws VolleyError In the event that the retry could not be performed (for example if we\n     * ran out of attempts), the passed in error is thrown.\n     */\n    public void retry(VolleyError error) throws VolleyError;\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/ServerError.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\n/**\n * Indicates that the server responded with an error response.\n */\n@SuppressWarnings(\"serial\")\npublic class ServerError extends VolleyError {\n    public ServerError(NetworkResponse networkResponse) {\n        super(networkResponse);\n    }\n\n    public ServerError() {\n        super();\n    }\n}\n\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/TimeoutError.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\n/**\n * Indicates that the connection or the socket timed out.\n */\n@SuppressWarnings(\"serial\")\npublic class TimeoutError extends VolleyError { }\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/VolleyError.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\n\nimport com.bzai.gamesdk.common.utils_base.proguard.ProguardInterface;\n\n/**\n * Exception style class encapsulating Volley errors\n */\n@SuppressWarnings(\"serial\")\npublic class VolleyError extends Exception implements ProguardInterface {\n    public final NetworkResponse networkResponse;\n    private long networkTimeMs;\n\n    public VolleyError() {\n        networkResponse = null;\n    }\n\n    public VolleyError(NetworkResponse response) {\n        networkResponse = response;\n    }\n\n    public VolleyError(String exceptionMessage) {\n       super(exceptionMessage);\n       networkResponse = null;\n    }\n\n    public VolleyError(String exceptionMessage, Throwable reason) {\n        super(exceptionMessage, reason);\n        networkResponse = null;\n    }\n\n    public VolleyError(Throwable cause) {\n        super(cause);\n        networkResponse = null;\n    }\n\n    /* package */ void setNetworkTimeMs(long networkTimeMs) {\n       this.networkTimeMs = networkTimeMs;\n    }\n\n    public long getNetworkTimeMs() {\n       return networkTimeMs;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/VolleyLog.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley;\n\nimport android.os.SystemClock;\nimport android.util.Log;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\n\n/**\n * Logging helper class.\n * <p/>\n * to see Volley logs call:<br/>\n * {@code <android-sdk>/platform-tools/adb shell setprop log.tag.Volley VERBOSE}\n */\npublic class VolleyLog {\n    public static String TAG = \"Volley\";\n\n    public static boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);\n\n    /**\n     * Customize the log tag for your application, so that other apps\n     * using Volley don't mix their logs with yours.\n     * <br />\n     * Enable the log property for your tag before starting your app:\n     * <br />\n     * {@code adb shell setprop log.tag.&lt;tag&gt;}\n     */\n    public static void setTag(String tag) {\n        d(\"Changing log tag to %s\", tag);\n        TAG = tag;\n\n        // Reinitialize the DEBUG \"constant\"\n        DEBUG = Log.isLoggable(TAG, Log.VERBOSE);\n    }\n\n    public static void v(String format, Object... args) {\n        if (DEBUG) {\n            Log.v(TAG, buildMessage(format, args));\n        }\n    }\n\n    public static void d(String format, Object... args) {\n        Log.d(TAG, buildMessage(format, args));\n    }\n\n    public static void e(String format, Object... args) {\n        Log.e(TAG, buildMessage(format, args));\n    }\n\n    public static void e(Throwable tr, String format, Object... args) {\n        Log.e(TAG, buildMessage(format, args), tr);\n    }\n\n    public static void wtf(String format, Object... args) {\n        Log.wtf(TAG, buildMessage(format, args));\n    }\n\n    public static void wtf(Throwable tr, String format, Object... args) {\n        Log.wtf(TAG, buildMessage(format, args), tr);\n    }\n\n    /**\n     * Formats the caller's provided message and prepends useful info like\n     * calling thread ID and method name.\n     */\n    private static String buildMessage(String format, Object... args) {\n        String msg = (args == null) ? format : String.format(Locale.US, format, args);\n        StackTraceElement[] trace = new Throwable().fillInStackTrace().getStackTrace();\n\n        String caller = \"<unknown>\";\n        // Walk up the stack looking for the first caller outside of VolleyLog.\n        // It will be at least two frames up, so start there.\n        for (int i = 2; i < trace.length; i++) {\n            Class<?> clazz = trace[i].getClass();\n            if (!clazz.equals(VolleyLog.class)) {\n                String callingClass = trace[i].getClassName();\n                callingClass = callingClass.substring(callingClass.lastIndexOf('.') + 1);\n                callingClass = callingClass.substring(callingClass.lastIndexOf('$') + 1);\n\n                caller = callingClass + \".\" + trace[i].getMethodName();\n                break;\n            }\n        }\n        return String.format(Locale.US, \"[%d] %s: %s\",\n                Thread.currentThread().getId(), caller, msg);\n    }\n\n    /**\n     * A simple event log with records containing a name, thread ID, and timestamp.\n     */\n    static class MarkerLog {\n        public static final boolean ENABLED = VolleyLog.DEBUG;\n\n        /** Minimum duration from first marker to last in an marker log to warrant logging. */\n        private static final long MIN_DURATION_FOR_LOGGING_MS = 0;\n\n        private static class Marker {\n            public final String name;\n            public final long thread;\n            public final long time;\n\n            public Marker(String name, long thread, long time) {\n                this.name = name;\n                this.thread = thread;\n                this.time = time;\n            }\n        }\n\n        private final List<Marker> mMarkers = new ArrayList<Marker>();\n        private boolean mFinished = false;\n\n        /** Adds a marker to this log with the specified name. */\n        public synchronized void add(String name, long threadId) {\n            if (mFinished) {\n                throw new IllegalStateException(\"Marker added to finished log\");\n            }\n\n            mMarkers.add(new Marker(name, threadId, SystemClock.elapsedRealtime()));\n        }\n\n        /**\n         * Closes the log, dumping it to logcat if the time difference between\n         * the first and last markers is greater than {@link #MIN_DURATION_FOR_LOGGING_MS}.\n         * @param header Header string to print above the marker log.\n         */\n        public synchronized void finish(String header) {\n            mFinished = true;\n\n            long duration = getTotalDuration();\n            if (duration <= MIN_DURATION_FOR_LOGGING_MS) {\n                return;\n            }\n\n            long prevTime = mMarkers.get(0).time;\n            d(\"(%-4d ms) %s\", duration, header);\n            for (Marker marker : mMarkers) {\n                long thisTime = marker.time;\n                d(\"(+%-4d) [%2d] %s\", (thisTime - prevTime), marker.thread, marker.name);\n                prevTime = thisTime;\n            }\n        }\n\n        @Override\n        protected void finalize() throws Throwable {\n            // Catch requests that have been collected (and hence end-of-lifed)\n            // but had no debugging output printed for them.\n            if (!mFinished) {\n                finish(\"Request on the loose\");\n                e(\"Marker log finalized without finish() - uncaught exit point for request\");\n            }\n        }\n\n        /** Returns the time difference between the first and last events in this log. */\n        private long getTotalDuration() {\n            if (mMarkers.size() == 0) {\n                return 0;\n            }\n\n            long first = mMarkers.get(0).time;\n            long last = mMarkers.get(mMarkers.size() - 1).time;\n            return last - first;\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/AndroidAuthenticator.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.accounts.AccountManagerFuture;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.AuthFailureError;\n\n/**\n * An Authenticator that uses {@link AccountManager} to get auth\n * tokens of a specified type for a specified account.\n */\npublic class AndroidAuthenticator implements Authenticator {\n    private final AccountManager mAccountManager;\n    private final Account mAccount;\n    private final String mAuthTokenType;\n    private final boolean mNotifyAuthFailure;\n\n    /**\n     * Creates a new authenticator.\n     * @param context Context for accessing AccountManager\n     * @param account Account to authenticate as\n     * @param authTokenType Auth token type passed to AccountManager\n     */\n    public AndroidAuthenticator(Context context, Account account, String authTokenType) {\n        this(context, account, authTokenType, false);\n    }\n\n    /**\n     * Creates a new authenticator.\n     * @param context Context for accessing AccountManager\n     * @param account Account to authenticate as\n     * @param authTokenType Auth token type passed to AccountManager\n     * @param notifyAuthFailure Whether to raise a notification upon auth failure\n     */\n    public AndroidAuthenticator(Context context, Account account, String authTokenType,\n                                boolean notifyAuthFailure) {\n        this(AccountManager.get(context), account, authTokenType, notifyAuthFailure);\n    }\n\n    // Visible for testing. Allows injection of a mock AccountManager.\n    AndroidAuthenticator(AccountManager accountManager, Account account,\n                         String authTokenType, boolean notifyAuthFailure) {\n        mAccountManager = accountManager;\n        mAccount = account;\n        mAuthTokenType = authTokenType;\n        mNotifyAuthFailure = notifyAuthFailure;\n    }\n\n    /**\n     * Returns the Account being used by this authenticator.\n     */\n    public Account getAccount() {\n        return mAccount;\n    }\n\n    // TODO: Figure out what to do about notifyAuthFailure\n    @SuppressWarnings(\"deprecation\")\n    @Override\n    public String getAuthToken() throws AuthFailureError {\n        AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(mAccount,\n                mAuthTokenType, mNotifyAuthFailure, null, null);\n        Bundle result;\n        try {\n            result = future.getResult();\n        } catch (Exception e) {\n            throw new AuthFailureError(\"Error while retrieving auth token\", e);\n        }\n        String authToken = null;\n        if (future.isDone() && !future.isCancelled()) {\n            if (result.containsKey(AccountManager.KEY_INTENT)) {\n                Intent intent = result.getParcelable(AccountManager.KEY_INTENT);\n                throw new AuthFailureError(intent);\n            }\n            authToken = result.getString(AccountManager.KEY_AUTHTOKEN);\n        }\n        if (authToken == null) {\n            throw new AuthFailureError(\"Got null auth token for type: \" + mAuthTokenType);\n        }\n\n        return authToken;\n    }\n\n    @Override\n    public void invalidateAuthToken(String authToken) {\n        mAccountManager.invalidateAuthToken(mAccount.type, authToken);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/Authenticator.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.AuthFailureError;\n\n/**\n * An interface for interacting with auth tokens.\n */\npublic interface Authenticator {\n    /**\n     * Synchronously retrieves an auth token.\n     *\n     * @throws AuthFailureError If authentication did not succeed\n     */\n    public String getAuthToken() throws AuthFailureError;\n\n    /**\n     * Invalidates the provided auth token.\n     */\n    public void invalidateAuthToken(String authToken);\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/BasicNetwork.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport android.os.SystemClock;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.AuthFailureError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Cache;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Network;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NetworkError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NetworkResponse;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NoConnectionError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.RedirectError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.RetryPolicy;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.ServerError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.TimeoutError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyLog;\n\nimport org.apache.http.Header;\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.HttpStatus;\nimport org.apache.http.StatusLine;\nimport org.apache.http.conn.ConnectTimeoutException;\nimport org.apache.http.impl.cookie.DateUtils;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.MalformedURLException;\nimport java.net.SocketTimeoutException;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.TreeMap;\n\n/**\n * A network performing Volley requests over an {@link HttpStack}.\n */\npublic class BasicNetwork implements Network {\n    protected static final boolean DEBUG = VolleyLog.DEBUG;\n\n    private static int SLOW_REQUEST_THRESHOLD_MS = 3000;\n\n    private static int DEFAULT_POOL_SIZE = 4096;\n\n    protected final HttpStack mHttpStack;\n\n    protected final ByteArrayPool mPool;\n\n    /**\n     * @param httpStack HTTP stack to be used\n     */\n    public BasicNetwork(HttpStack httpStack) {\n        // If a pool isn't passed in, then build a small default pool that will give us a lot of\n        // benefit and not use too much memory.\n        this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));\n    }\n\n    /**\n     * @param httpStack HTTP stack to be used\n     * @param pool a buffer pool that improves GC performance in copy operations\n     */\n    public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {\n        mHttpStack = httpStack;\n        mPool = pool;\n    }\n\n    @Override\n    public NetworkResponse performRequest(Request<?> request) throws VolleyError {\n        long requestStart = SystemClock.elapsedRealtime();\n        while (true) {\n            HttpResponse httpResponse = null;\n            byte[] responseContents = null;\n            Map<String, String> responseHeaders = Collections.emptyMap();\n            try {\n                // Gather headers.\n                Map<String, String> headers = new HashMap<String, String>();\n                addCacheHeaders(headers, request.getCacheEntry());\n                httpResponse = mHttpStack.performRequest(request, headers);\n                StatusLine statusLine = httpResponse.getStatusLine();\n                int statusCode = statusLine.getStatusCode();\n\n                responseHeaders = convertHeaders(httpResponse.getAllHeaders());\n                // Handle cache validation.\n                if (statusCode == HttpStatus.SC_NOT_MODIFIED) {\n\n                    Cache.Entry entry = request.getCacheEntry();\n                    if (entry == null) {\n                        return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,\n                                responseHeaders, true,\n                                SystemClock.elapsedRealtime() - requestStart);\n                    }\n\n                    // A HTTP 304 response does not have all header fields. We\n                    // have to use the header fields from the cache entry plus\n                    // the new ones from the response.\n                    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5\n                    entry.responseHeaders.putAll(responseHeaders);\n                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,\n                            entry.responseHeaders, true,\n                            SystemClock.elapsedRealtime() - requestStart);\n                }\n                \n                // Handle moved resources\n                if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {\n                \tString newUrl = responseHeaders.get(\"Location\");\n                \trequest.setRedirectUrl(newUrl);\n                }\n\n                // Some responses such as 204s do not have content.  We must check.\n                if (httpResponse.getEntity() != null) {\n                  responseContents = entityToBytes(httpResponse.getEntity());\n                } else {\n                  // Add 0 byte response as a way of honestly representing a\n                  // no-content request.\n                  responseContents = new byte[0];\n                }\n\n                // if the request is slow, log it.\n                long requestLifetime = SystemClock.elapsedRealtime() - requestStart;\n                logSlowRequests(requestLifetime, request, responseContents, statusLine);\n\n                if (statusCode < 200 || statusCode > 299) {\n                    throw new IOException();\n                }\n                return new NetworkResponse(statusCode, responseContents, responseHeaders, false,\n                        SystemClock.elapsedRealtime() - requestStart);\n            } catch (SocketTimeoutException e) {\n                attemptRetryOnException(\"socket\", request, new TimeoutError());\n            } catch (ConnectTimeoutException e) {\n                attemptRetryOnException(\"connection\", request, new TimeoutError());\n            } catch (MalformedURLException e) {\n                throw new RuntimeException(\"Bad URL \" + request.getUrl(), e);\n            } catch (IOException e) {\n                int statusCode = 0;\n                NetworkResponse networkResponse = null;\n                if (httpResponse != null) {\n                    statusCode = httpResponse.getStatusLine().getStatusCode();\n                } else {\n                    throw new NoConnectionError(e);\n                }\n                if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||\n                \t\tstatusCode == HttpStatus.SC_MOVED_TEMPORARILY) {\n                \tVolleyLog.e(\"Request at %s has been redirected to %s\", request.getOriginUrl(), request.getUrl());\n                } else {\n                \tVolleyLog.e(\"Unexpected response code %d for %s\", statusCode, request.getUrl());\n                }\n                if (responseContents != null) {\n                    networkResponse = new NetworkResponse(statusCode, responseContents,\n                            responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);\n                    if (statusCode == HttpStatus.SC_UNAUTHORIZED ||\n                            statusCode == HttpStatus.SC_FORBIDDEN) {\n                        attemptRetryOnException(\"auth\",\n                                request, new AuthFailureError(networkResponse));\n                    } else if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||\n                    \t\t\tstatusCode == HttpStatus.SC_MOVED_TEMPORARILY) {\n                        attemptRetryOnException(\"redirect\",\n                                request, new RedirectError(networkResponse));\n                    } else {\n                        // TODO: Only throw ServerError for 5xx status codes.\n                        throw new ServerError(networkResponse);\n                    }\n                } else {\n                    throw new NetworkError(e);\n                }\n            }\n        }\n    }\n\n    /**\n     * Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete.\n     */\n    private void logSlowRequests(long requestLifetime, Request<?> request,\n            byte[] responseContents, StatusLine statusLine) {\n        if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) {\n            VolleyLog.d(\"HTTP response for request=<%s> [lifetime=%d], [size=%s], \" +\n                    \"[rc=%d], [retryCount=%s]\", request, requestLifetime,\n                    responseContents != null ? responseContents.length : \"null\",\n                    statusLine.getStatusCode(), request.getRetryPolicy().getCurrentRetryCount());\n        }\n    }\n\n    /**\n     * Attempts to prepare the request for a retry. If there are no more attempts remaining in the\n     * request's retry policy, a timeout exception is thrown.\n     * @param request The request to use.\n     */\n    private static void attemptRetryOnException(String logPrefix, Request<?> request,\n                                                VolleyError exception) throws VolleyError {\n        RetryPolicy retryPolicy = request.getRetryPolicy();\n        int oldTimeout = request.getTimeoutMs();\n\n        try {\n            retryPolicy.retry(exception);\n        } catch (VolleyError e) {\n            request.addMarker(\n                    String.format(\"%s-timeout-giveup [timeout=%s]\", logPrefix, oldTimeout));\n            throw e;\n        }\n        request.addMarker(String.format(\"%s-retry [timeout=%s]\", logPrefix, oldTimeout));\n    }\n\n    private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) {\n        // If there's no cache entry, we're done.\n        if (entry == null) {\n            return;\n        }\n\n        if (entry.etag != null) {\n            headers.put(\"If-None-Match\", entry.etag);\n        }\n\n        if (entry.lastModified > 0) {\n            Date refTime = new Date(entry.lastModified);\n            headers.put(\"If-Modified-Since\", DateUtils.formatDate(refTime));\n        }\n    }\n\n    protected void logError(String what, String url, long start) {\n        long now = SystemClock.elapsedRealtime();\n        VolleyLog.v(\"HTTP ERROR(%s) %d ms to fetch %s\", what, (now - start), url);\n    }\n\n    /** Reads the contents of HttpEntity into a byte[]. */\n    private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {\n        PoolingByteArrayOutputStream bytes =\n                new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());\n        byte[] buffer = null;\n        try {\n            InputStream in = entity.getContent();\n            if (in == null) {\n                throw new ServerError();\n            }\n            buffer = mPool.getBuf(1024);\n            int count;\n            while ((count = in.read(buffer)) != -1) {\n                bytes.write(buffer, 0, count);\n            }\n            return bytes.toByteArray();\n        } finally {\n            try {\n                // Close the InputStream and release the resources by \"consuming the content\".\n                entity.consumeContent();\n            } catch (IOException e) {\n                // This can happen if there was an exception above that left the entity in\n                // an invalid state.\n                VolleyLog.v(\"Error occured when calling consumingContent\");\n            }\n            mPool.returnBuf(buffer);\n            bytes.close();\n        }\n    }\n\n    /**\n     * Converts Headers[] to Map<String, String>.\n     */\n    protected static Map<String, String> convertHeaders(Header[] headers) {\n        Map<String, String> result = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);\n        for (int i = 0; i < headers.length; i++) {\n            result.put(headers[i].getName(), headers[i].getValue());\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/ByteArrayPool.java",
    "content": "/*\n * Copyright (C) 2012 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * ByteArrayPool is a source and repository of <code>byte[]</code> objects. Its purpose is to\n * supply those buffers to consumers who need to use them for a short period of time and then\n * dispose of them. Simply creating and disposing such buffers in the conventional manner can\n * considerable heap churn and garbage collection delays on Android, which lacks good management of\n * short-lived heap objects. It may be advantageous to trade off some memory in the form of a\n * permanently allocated pool of buffers in order to gain heap performance improvements; that is\n * what this class does.\n * <p>\n * A good candidate user for this class is something like an I/O system that uses large temporary\n * <code>byte[]</code> buffers to copy data around. In these use cases, often the consumer wants\n * the buffer to be a certain minimum size to ensure good performance (e.g. when copying data chunks\n * off of a stream), but doesn't mind if the buffer is larger than the minimum. Taking this into\n * account and also to maximize the odds of being able to reuse a recycled buffer, this class is\n * free to return buffers larger than the requested size. The caller needs to be able to gracefully\n * deal with getting buffers any size over the minimum.\n * <p>\n * If there is not a suitably-sized buffer in its recycling pool when a buffer is requested, this\n * class will allocate a new buffer and return it.\n * <p>\n * This class has no special ownership of buffers it creates; the caller is free to take a buffer\n * it receives from this pool, use it permanently, and never return it to the pool; additionally,\n * it is not harmful to return to this pool a buffer that was allocated elsewhere, provided there\n * are no other lingering references to it.\n * <p>\n * This class ensures that the total size of the buffers in its recycling pool never exceeds a\n * certain byte limit. When a buffer is returned that would cause the pool to exceed the limit,\n * least-recently-used buffers are disposed.\n */\npublic class ByteArrayPool {\n    /** The buffer pool, arranged both by last use and by buffer size */\n    private List<byte[]> mBuffersByLastUse = new LinkedList<byte[]>();\n    private List<byte[]> mBuffersBySize = new ArrayList<byte[]>(64);\n\n    /** The total size of the buffers in the pool */\n    private int mCurrentSize = 0;\n\n    /**\n     * The maximum aggregate size of the buffers in the pool. Old buffers are discarded to stay\n     * under this limit.\n     */\n    private final int mSizeLimit;\n\n    /** Compares buffers by size */\n    protected static final Comparator<byte[]> BUF_COMPARATOR = new Comparator<byte[]>() {\n        @Override\n        public int compare(byte[] lhs, byte[] rhs) {\n            return lhs.length - rhs.length;\n        }\n    };\n\n    /**\n     * @param sizeLimit the maximum size of the pool, in bytes\n     */\n    public ByteArrayPool(int sizeLimit) {\n        mSizeLimit = sizeLimit;\n    }\n\n    /**\n     * Returns a buffer from the pool if one is available in the requested size, or allocates a new\n     * one if a pooled one is not available.\n     *\n     * @param len the minimum size, in bytes, of the requested buffer. The returned buffer may be\n     *        larger.\n     * @return a byte[] buffer is always returned.\n     */\n    public synchronized byte[] getBuf(int len) {\n        for (int i = 0; i < mBuffersBySize.size(); i++) {\n            byte[] buf = mBuffersBySize.get(i);\n            if (buf.length >= len) {\n                mCurrentSize -= buf.length;\n                mBuffersBySize.remove(i);\n                mBuffersByLastUse.remove(buf);\n                return buf;\n            }\n        }\n        return new byte[len];\n    }\n\n    /**\n     * Returns a buffer to the pool, throwing away old buffers if the pool would exceed its allotted\n     * size.\n     *\n     * @param buf the buffer to return to the pool.\n     */\n    public synchronized void returnBuf(byte[] buf) {\n        if (buf == null || buf.length > mSizeLimit) {\n            return;\n        }\n        mBuffersByLastUse.add(buf);\n        int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR);\n        if (pos < 0) {\n            pos = -pos - 1;\n        }\n        mBuffersBySize.add(pos, buf);\n        mCurrentSize += buf.length;\n        trim();\n    }\n\n    /**\n     * Removes buffers from the pool until it is under its size limit.\n     */\n    private synchronized void trim() {\n        while (mCurrentSize > mSizeLimit) {\n            byte[] buf = mBuffersByLastUse.remove(0);\n            mBuffersBySize.remove(buf);\n            mCurrentSize -= buf.length;\n        }\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/ClearCacheRequest.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport android.os.Handler;\nimport android.os.Looper;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Cache;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NetworkResponse;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response;\n\n/**\n * A synthetic request used for clearing the cache.\n */\npublic class ClearCacheRequest extends Request<Object> {\n    private final Cache mCache;\n    private final Runnable mCallback;\n\n    /**\n     * Creates a synthetic request for clearing the cache.\n     * @param cache Cache to clear\n     * @param callback Callback to make on the main thread once the cache is clear,\n     * or null for none\n     */\n    public ClearCacheRequest(Cache cache, Runnable callback) {\n        super(Method.GET, null, null);\n        mCache = cache;\n        mCallback = callback;\n    }\n\n    @Override\n    public boolean isCanceled() {\n        // This is a little bit of a hack, but hey, why not.\n        mCache.clear();\n        if (mCallback != null) {\n            Handler handler = new Handler(Looper.getMainLooper());\n            handler.postAtFrontOfQueue(mCallback);\n        }\n        return true;\n    }\n\n    @Override\n    public Priority getPriority() {\n        return Priority.IMMEDIATE;\n    }\n\n    @Override\n    protected Response<Object> parseNetworkResponse(NetworkResponse response) {\n        return null;\n    }\n\n    @Override\n    protected void deliverResponse(Object response) {\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/DiskBasedCache.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport android.os.SystemClock;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Cache;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyLog;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.EOFException;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * Cache implementation that caches files directly onto the hard disk in the specified\n * directory. The default disk usage size is 5MB, but is configurable.\n */\npublic class DiskBasedCache implements Cache {\n\n    /** Map of the Key, CacheHeader pairs */\n    private final Map<String, CacheHeader> mEntries =\n            new LinkedHashMap<String, CacheHeader>(16, .75f, true);\n\n    /** Total amount of space currently used by the cache in bytes. */\n    private long mTotalSize = 0;\n\n    /** The root directory to use for the cache. */\n    private final File mRootDirectory;\n\n    /** The maximum size of the cache in bytes. */\n    private final int mMaxCacheSizeInBytes;\n\n    /** Default maximum disk usage in bytes. */\n    private static final int DEFAULT_DISK_USAGE_BYTES = 5 * 1024 * 1024;\n\n    /** High water mark percentage for the cache */\n    private static final float HYSTERESIS_FACTOR = 0.9f;\n\n    /** Magic number for current version of cache file format. */\n    private static final int CACHE_MAGIC = 0x20150306;\n\n    /**\n     * Constructs an instance of the DiskBasedCache at the specified directory.\n     * @param rootDirectory The root directory of the cache.\n     * @param maxCacheSizeInBytes The maximum size of the cache in bytes.\n     */\n    public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes) {\n        mRootDirectory = rootDirectory;\n        mMaxCacheSizeInBytes = maxCacheSizeInBytes;\n    }\n\n    /**\n     * Constructs an instance of the DiskBasedCache at the specified directory using\n     * the default maximum cache size of 5MB.\n     * @param rootDirectory The root directory of the cache.\n     */\n    public DiskBasedCache(File rootDirectory) {\n        this(rootDirectory, DEFAULT_DISK_USAGE_BYTES);\n    }\n\n    /**\n     * Clears the cache. Deletes all cached files from disk.\n     */\n    @Override\n    public synchronized void clear() {\n        File[] files = mRootDirectory.listFiles();\n        if (files != null) {\n            for (File file : files) {\n                file.delete();\n            }\n        }\n        mEntries.clear();\n        mTotalSize = 0;\n        VolleyLog.d(\"Cache cleared.\");\n    }\n\n    /**\n     * Returns the cache entry with the specified key if it exists, null otherwise.\n     */\n    @Override\n    public synchronized Entry get(String key) {\n        CacheHeader entry = mEntries.get(key);\n        // if the entry does not exist, return.\n        if (entry == null) {\n            return null;\n        }\n\n        File file = getFileForKey(key);\n        CountingInputStream cis = null;\n        try {\n            cis = new CountingInputStream(new BufferedInputStream(new FileInputStream(file)));\n            CacheHeader.readHeader(cis); // eat header\n            byte[] data = streamToBytes(cis, (int) (file.length() - cis.bytesRead));\n            return entry.toCacheEntry(data);\n        } catch (IOException e) {\n            VolleyLog.d(\"%s: %s\", file.getAbsolutePath(), e.toString());\n            remove(key);\n            return null;\n        }  catch (NegativeArraySizeException e) {\n            VolleyLog.d(\"%s: %s\", file.getAbsolutePath(), e.toString());\n            remove(key);\n            return null;\n        } finally {\n            if (cis != null) {\n                try {\n                    cis.close();\n                } catch (IOException ioe) {\n                    return null;\n                }\n            }\n        }\n    }\n\n    /**\n     * Initializes the DiskBasedCache by scanning for all files currently in the\n     * specified root directory. Creates the root directory if necessary.\n     */\n    @Override\n    public synchronized void initialize() {\n        if (!mRootDirectory.exists()) {\n            if (!mRootDirectory.mkdirs()) {\n                VolleyLog.e(\"Unable to create cache dir %s\", mRootDirectory.getAbsolutePath());\n            }\n            return;\n        }\n\n        File[] files = mRootDirectory.listFiles();\n        if (files == null) {\n            return;\n        }\n        for (File file : files) {\n            BufferedInputStream fis = null;\n            try {\n                fis = new BufferedInputStream(new FileInputStream(file));\n                CacheHeader entry = CacheHeader.readHeader(fis);\n                entry.size = file.length();\n                putEntry(entry.key, entry);\n            } catch (IOException e) {\n                if (file != null) {\n                   file.delete();\n                }\n            } finally {\n                try {\n                    if (fis != null) {\n                        fis.close();\n                    }\n                } catch (IOException ignored) { }\n            }\n        }\n    }\n\n    /**\n     * Invalidates an entry in the cache.\n     * @param key Cache key\n     * @param fullExpire True to fully expire the entry, false to soft expire\n     */\n    @Override\n    public synchronized void invalidate(String key, boolean fullExpire) {\n        Entry entry = get(key);\n        if (entry != null) {\n            entry.softTtl = 0;\n            if (fullExpire) {\n                entry.ttl = 0;\n            }\n            put(key, entry);\n        }\n\n    }\n\n    /**\n     * Puts the entry with the specified key into the cache.\n     */\n    @Override\n    public synchronized void put(String key, Entry entry) {\n        pruneIfNeeded(entry.data.length);\n        File file = getFileForKey(key);\n        try {\n            BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(file));\n            CacheHeader e = new CacheHeader(key, entry);\n            boolean success = e.writeHeader(fos);\n            if (!success) {\n                fos.close();\n                VolleyLog.d(\"Failed to write header for %s\", file.getAbsolutePath());\n                throw new IOException();\n            }\n            fos.write(entry.data);\n            fos.close();\n            putEntry(key, e);\n            return;\n        } catch (IOException e) {\n        }\n        boolean deleted = file.delete();\n        if (!deleted) {\n            VolleyLog.d(\"Could not clean up file %s\", file.getAbsolutePath());\n        }\n    }\n\n    /**\n     * Removes the specified key from the cache if it exists.\n     */\n    @Override\n    public synchronized void remove(String key) {\n        boolean deleted = getFileForKey(key).delete();\n        removeEntry(key);\n        if (!deleted) {\n            VolleyLog.d(\"Could not delete cache entry for key=%s, filename=%s\",\n                    key, getFilenameForKey(key));\n        }\n    }\n\n    /**\n     * Creates a pseudo-unique filename for the specified cache key.\n     * @param key The key to generate a file name for.\n     * @return A pseudo-unique filename.\n     */\n    private String getFilenameForKey(String key) {\n        int firstHalfLength = key.length() / 2;\n        String localFilename = String.valueOf(key.substring(0, firstHalfLength).hashCode());\n        localFilename += String.valueOf(key.substring(firstHalfLength).hashCode());\n        return localFilename;\n    }\n\n    /**\n     * Returns a file object for the given cache key.\n     */\n    public File getFileForKey(String key) {\n        return new File(mRootDirectory, getFilenameForKey(key));\n    }\n\n    /**\n     * Prunes the cache to fit the amount of bytes specified.\n     * @param neededSpace The amount of bytes we are trying to fit into the cache.\n     */\n    private void pruneIfNeeded(int neededSpace) {\n        if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes) {\n            return;\n        }\n        if (VolleyLog.DEBUG) {\n            VolleyLog.v(\"Pruning old cache entries.\");\n        }\n\n        long before = mTotalSize;\n        int prunedFiles = 0;\n        long startTime = SystemClock.elapsedRealtime();\n\n        Iterator<Map.Entry<String, CacheHeader>> iterator = mEntries.entrySet().iterator();\n        while (iterator.hasNext()) {\n            Map.Entry<String, CacheHeader> entry = iterator.next();\n            CacheHeader e = entry.getValue();\n            boolean deleted = getFileForKey(e.key).delete();\n            if (deleted) {\n                mTotalSize -= e.size;\n            } else {\n               VolleyLog.d(\"Could not delete cache entry for key=%s, filename=%s\",\n                       e.key, getFilenameForKey(e.key));\n            }\n            iterator.remove();\n            prunedFiles++;\n\n            if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) {\n                break;\n            }\n        }\n\n        if (VolleyLog.DEBUG) {\n            VolleyLog.v(\"pruned %d files, %d bytes, %d ms\",\n                    prunedFiles, (mTotalSize - before), SystemClock.elapsedRealtime() - startTime);\n        }\n    }\n\n    /**\n     * Puts the entry with the specified key into the cache.\n     * @param key The key to identify the entry by.\n     * @param entry The entry to cache.\n     */\n    private void putEntry(String key, CacheHeader entry) {\n        if (!mEntries.containsKey(key)) {\n            mTotalSize += entry.size;\n        } else {\n            CacheHeader oldEntry = mEntries.get(key);\n            mTotalSize += (entry.size - oldEntry.size);\n        }\n        mEntries.put(key, entry);\n    }\n\n    /**\n     * Removes the entry identified by 'key' from the cache.\n     */\n    private void removeEntry(String key) {\n        CacheHeader entry = mEntries.get(key);\n        if (entry != null) {\n            mTotalSize -= entry.size;\n            mEntries.remove(key);\n        }\n    }\n\n    /**\n     * Reads the contents of an InputStream into a byte[].\n     * */\n    private static byte[] streamToBytes(InputStream in, int length) throws IOException {\n        byte[] bytes = new byte[length];\n        int count;\n        int pos = 0;\n        while (pos < length && ((count = in.read(bytes, pos, length - pos)) != -1)) {\n            pos += count;\n        }\n        if (pos != length) {\n            throw new IOException(\"Expected \" + length + \" bytes, read \" + pos + \" bytes\");\n        }\n        return bytes;\n    }\n\n    /**\n     * Handles holding onto the cache headers for an entry.\n     */\n    // Visible for testing.\n    static class CacheHeader {\n        /** The size of the data identified by this CacheHeader. (This is not\n         * serialized to disk. */\n        public long size;\n\n        /** The key that identifies the cache entry. */\n        public String key;\n\n        /** ETag for cache coherence. */\n        public String etag;\n\n        /** Date of this response as reported by the server. */\n        public long serverDate;\n\n        /** The last modified date for the requested object. */\n        public long lastModified;\n\n        /** TTL for this record. */\n        public long ttl;\n\n        /** Soft TTL for this record. */\n        public long softTtl;\n\n        /** Headers from the response resulting in this cache entry. */\n        public Map<String, String> responseHeaders;\n\n        private CacheHeader() { }\n\n        /**\n         * Instantiates a new CacheHeader object\n         * @param key The key that identifies the cache entry\n         * @param entry The cache entry.\n         */\n        public CacheHeader(String key, Entry entry) {\n            this.key = key;\n            this.size = entry.data.length;\n            this.etag = entry.etag;\n            this.serverDate = entry.serverDate;\n            this.lastModified = entry.lastModified;\n            this.ttl = entry.ttl;\n            this.softTtl = entry.softTtl;\n            this.responseHeaders = entry.responseHeaders;\n        }\n\n        /**\n         * Reads the header off of an InputStream and returns a CacheHeader object.\n         * @param is The InputStream to read from.\n         * @throws IOException\n         */\n        public static CacheHeader readHeader(InputStream is) throws IOException {\n            CacheHeader entry = new CacheHeader();\n            int magic = readInt(is);\n            if (magic != CACHE_MAGIC) {\n                // don't bother deleting, it'll get pruned eventually\n                throw new IOException();\n            }\n            entry.key = readString(is);\n            entry.etag = readString(is);\n            if (entry.etag.equals(\"\")) {\n                entry.etag = null;\n            }\n            entry.serverDate = readLong(is);\n            entry.lastModified = readLong(is);\n            entry.ttl = readLong(is);\n            entry.softTtl = readLong(is);\n            entry.responseHeaders = readStringStringMap(is);\n\n            return entry;\n        }\n\n        /**\n         * Creates a cache entry for the specified data.\n         */\n        public Entry toCacheEntry(byte[] data) {\n            Entry e = new Entry();\n            e.data = data;\n            e.etag = etag;\n            e.serverDate = serverDate;\n            e.lastModified = lastModified;\n            e.ttl = ttl;\n            e.softTtl = softTtl;\n            e.responseHeaders = responseHeaders;\n            return e;\n        }\n\n\n        /**\n         * Writes the contents of this CacheHeader to the specified OutputStream.\n         */\n        public boolean writeHeader(OutputStream os) {\n            try {\n                writeInt(os, CACHE_MAGIC);\n                writeString(os, key);\n                writeString(os, etag == null ? \"\" : etag);\n                writeLong(os, serverDate);\n                writeLong(os, lastModified);\n                writeLong(os, ttl);\n                writeLong(os, softTtl);\n                writeStringStringMap(responseHeaders, os);\n                os.flush();\n                return true;\n            } catch (IOException e) {\n                VolleyLog.d(\"%s\", e.toString());\n                return false;\n            }\n        }\n\n    }\n\n    private static class CountingInputStream extends FilterInputStream {\n        private int bytesRead = 0;\n\n        private CountingInputStream(InputStream in) {\n            super(in);\n        }\n\n        @Override\n        public int read() throws IOException {\n            int result = super.read();\n            if (result != -1) {\n                bytesRead++;\n            }\n            return result;\n        }\n\n        @Override\n        public int read(byte[] buffer, int offset, int count) throws IOException {\n            int result = super.read(buffer, offset, count);\n            if (result != -1) {\n                bytesRead += result;\n            }\n            return result;\n        }\n    }\n\n    /*\n     * Homebrewed simple serialization system used for reading and writing cache\n     * headers on disk. Once upon a time, this used the standard Java\n     * Object{Input,Output}Stream, but the default implementation relies heavily\n     * on reflection (even for standard types) and generates a ton of garbage.\n     */\n\n    /**\n     * Simple wrapper around {@link InputStream#read()} that throws EOFException\n     * instead of returning -1.\n     */\n    private static int read(InputStream is) throws IOException {\n        int b = is.read();\n        if (b == -1) {\n            throw new EOFException();\n        }\n        return b;\n    }\n\n    static void writeInt(OutputStream os, int n) throws IOException {\n        os.write((n >> 0) & 0xff);\n        os.write((n >> 8) & 0xff);\n        os.write((n >> 16) & 0xff);\n        os.write((n >> 24) & 0xff);\n    }\n\n    static int readInt(InputStream is) throws IOException {\n        int n = 0;\n        n |= (read(is) << 0);\n        n |= (read(is) << 8);\n        n |= (read(is) << 16);\n        n |= (read(is) << 24);\n        return n;\n    }\n\n    static void writeLong(OutputStream os, long n) throws IOException {\n        os.write((byte)(n >>> 0));\n        os.write((byte)(n >>> 8));\n        os.write((byte)(n >>> 16));\n        os.write((byte)(n >>> 24));\n        os.write((byte)(n >>> 32));\n        os.write((byte)(n >>> 40));\n        os.write((byte)(n >>> 48));\n        os.write((byte)(n >>> 56));\n    }\n\n    static long readLong(InputStream is) throws IOException {\n        long n = 0;\n        n |= ((read(is) & 0xFFL) << 0);\n        n |= ((read(is) & 0xFFL) << 8);\n        n |= ((read(is) & 0xFFL) << 16);\n        n |= ((read(is) & 0xFFL) << 24);\n        n |= ((read(is) & 0xFFL) << 32);\n        n |= ((read(is) & 0xFFL) << 40);\n        n |= ((read(is) & 0xFFL) << 48);\n        n |= ((read(is) & 0xFFL) << 56);\n        return n;\n    }\n\n    static void writeString(OutputStream os, String s) throws IOException {\n        byte[] b = s.getBytes(\"UTF-8\");\n        writeLong(os, b.length);\n        os.write(b, 0, b.length);\n    }\n\n    static String readString(InputStream is) throws IOException {\n        int n = (int) readLong(is);\n        byte[] b = streamToBytes(is, n);\n        return new String(b, \"UTF-8\");\n    }\n\n    static void writeStringStringMap(Map<String, String> map, OutputStream os) throws IOException {\n        if (map != null) {\n            writeInt(os, map.size());\n            for (Map.Entry<String, String> entry : map.entrySet()) {\n                writeString(os, entry.getKey());\n                writeString(os, entry.getValue());\n            }\n        } else {\n            writeInt(os, 0);\n        }\n    }\n\n    static Map<String, String> readStringStringMap(InputStream is) throws IOException {\n        int size = readInt(is);\n        Map<String, String> result = (size == 0)\n                ? Collections.<String, String>emptyMap()\n                : new HashMap<String, String>(size);\n        for (int i = 0; i < size; i++) {\n            String key = readString(is).intern();\n            String value = readString(is).intern();\n            result.put(key, value);\n        }\n        return result;\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/HttpClientStack.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.AuthFailureError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.methods.HttpDelete;\nimport org.apache.http.client.methods.HttpEntityEnclosingRequestBase;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpHead;\nimport org.apache.http.client.methods.HttpOptions;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.client.methods.HttpPut;\nimport org.apache.http.client.methods.HttpTrace;\nimport org.apache.http.client.methods.HttpUriRequest;\nimport org.apache.http.entity.ByteArrayEntity;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.apache.http.params.HttpConnectionParams;\nimport org.apache.http.params.HttpParams;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * An HttpStack that performs request over an {@link HttpClient}.\n */\npublic class HttpClientStack implements HttpStack {\n    protected final HttpClient mClient;\n\n    private final static String HEADER_CONTENT_TYPE = \"Content-Type\";\n\n    public HttpClientStack(HttpClient client) {\n        mClient = client;\n    }\n\n    private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {\n        for (String key : headers.keySet()) {\n            httpRequest.setHeader(key, headers.get(key));\n        }\n    }\n\n    @SuppressWarnings(\"unused\")\n    private static List<NameValuePair> getPostParameterPairs(Map<String, String> postParams) {\n        List<NameValuePair> result = new ArrayList<NameValuePair>(postParams.size());\n        for (String key : postParams.keySet()) {\n            result.add(new BasicNameValuePair(key, postParams.get(key)));\n        }\n        return result;\n    }\n\n    @Override\n    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)\n            throws IOException, AuthFailureError {\n        HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);\n        addHeaders(httpRequest, additionalHeaders);\n        addHeaders(httpRequest, request.getHeaders());\n        onPrepareRequest(httpRequest);\n        HttpParams httpParams = httpRequest.getParams();\n        int timeoutMs = request.getTimeoutMs();\n        // TODO: Reevaluate this connection timeout based on more wide-scale\n        // data collection and possibly different for wifi vs. 3G.\n        HttpConnectionParams.setConnectionTimeout(httpParams, 5000);\n        HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);\n        return mClient.execute(httpRequest);\n    }\n\n    /**\n     * Creates the appropriate subclass of HttpUriRequest for passed in request.\n     */\n    @SuppressWarnings(\"deprecation\")\n    /* protected */ static HttpUriRequest createHttpRequest(Request<?> request,\n                                                            Map<String, String> additionalHeaders) throws AuthFailureError {\n        switch (request.getMethod()) {\n            case Request.Method.DEPRECATED_GET_OR_POST: {\n                // This is the deprecated way that needs to be handled for backwards compatibility.\n                // If the request's post body is null, then the assumption is that the request is\n                // GET.  Otherwise, it is assumed that the request is a POST.\n                byte[] postBody = request.getPostBody();\n                if (postBody != null) {\n                    HttpPost postRequest = new HttpPost(request.getUrl());\n                    postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType());\n                    HttpEntity entity;\n                    entity = new ByteArrayEntity(postBody);\n                    postRequest.setEntity(entity);\n                    return postRequest;\n                } else {\n                    return new HttpGet(request.getUrl());\n                }\n            }\n            case Request.Method.GET:\n                return new HttpGet(request.getUrl());\n            case Request.Method.DELETE:\n                return new HttpDelete(request.getUrl());\n            case Request.Method.POST: {\n                HttpPost postRequest = new HttpPost(request.getUrl());\n                postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());\n                setEntityIfNonEmptyBody(postRequest, request);\n                return postRequest;\n            }\n            case Request.Method.PUT: {\n                HttpPut putRequest = new HttpPut(request.getUrl());\n                putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());\n                setEntityIfNonEmptyBody(putRequest, request);\n                return putRequest;\n            }\n            case Request.Method.HEAD:\n                return new HttpHead(request.getUrl());\n            case Request.Method.OPTIONS:\n                return new HttpOptions(request.getUrl());\n            case Request.Method.TRACE:\n                return new HttpTrace(request.getUrl());\n            case Request.Method.PATCH: {\n                HttpPatch patchRequest = new HttpPatch(request.getUrl());\n                patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());\n                setEntityIfNonEmptyBody(patchRequest, request);\n                return patchRequest;\n            }\n            default:\n                throw new IllegalStateException(\"Unknown request method.\");\n        }\n    }\n\n    private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest,\n            Request<?> request) throws AuthFailureError {\n        byte[] body = request.getBody();\n        if (body != null) {\n            HttpEntity entity = new ByteArrayEntity(body);\n            httpRequest.setEntity(entity);\n        }\n    }\n\n    /**\n     * Called before the request is executed using the underlying HttpClient.\n     *\n     * <p>Overwrite in subclasses to augment the request.</p>\n     */\n    protected void onPrepareRequest(HttpUriRequest request) throws IOException {\n        // Nothing.\n    }\n\n    /**\n     * The HttpPatch class does not exist in the Android framework, so this has been defined here.\n     */\n    public static final class HttpPatch extends HttpEntityEnclosingRequestBase {\n\n        public final static String METHOD_NAME = \"PATCH\";\n\n        public HttpPatch() {\n            super();\n        }\n\n        public HttpPatch(final URI uri) {\n            super();\n            setURI(uri);\n        }\n\n        /**\n         * @throws IllegalArgumentException if the uri is invalid.\n         */\n        public HttpPatch(final String uri) {\n            super();\n            setURI(URI.create(uri));\n        }\n\n        @Override\n        public String getMethod() {\n            return METHOD_NAME;\n        }\n\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/HttpHeaderParser.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Cache;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NetworkResponse;\n\nimport org.apache.http.impl.cookie.DateParseException;\nimport org.apache.http.impl.cookie.DateUtils;\nimport org.apache.http.protocol.HTTP;\n\nimport java.util.Map;\n\n/**\n * Utility methods for parsing HTTP headers.\n */\npublic class HttpHeaderParser {\n\n    /**\n     * Extracts a {@link Cache.Entry} from a {@link NetworkResponse}.\n     *\n     * @param response The network response to parse headers from\n     * @return a cache entry for the given response, or null if the response is not cacheable.\n     */\n    public static Cache.Entry parseCacheHeaders(NetworkResponse response) {\n        long now = System.currentTimeMillis();\n\n        Map<String, String> headers = response.headers;\n\n        long serverDate = 0;\n        long lastModified = 0;\n        long serverExpires = 0;\n        long softExpire = 0;\n        long finalExpire = 0;\n        long maxAge = 0;\n        long staleWhileRevalidate = 0;\n        boolean hasCacheControl = false;\n        boolean mustRevalidate = false;\n\n        String serverEtag = null;\n        String headerValue;\n\n        headerValue = headers.get(\"Date\");\n        if (headerValue != null) {\n            serverDate = parseDateAsEpoch(headerValue);\n        }\n\n        headerValue = headers.get(\"Cache-Control\");\n        if (headerValue != null) {\n            hasCacheControl = true;\n            String[] tokens = headerValue.split(\",\");\n            for (int i = 0; i < tokens.length; i++) {\n                String token = tokens[i].trim();\n                if (token.equals(\"no-cache\") || token.equals(\"no-store\")) {\n                    return null;\n                } else if (token.startsWith(\"max-age=\")) {\n                    try {\n                        maxAge = Long.parseLong(token.substring(8));\n                    } catch (Exception e) {\n                    }\n                } else if (token.startsWith(\"stale-while-revalidate=\")) {\n                    try {\n                        staleWhileRevalidate = Long.parseLong(token.substring(23));\n                    } catch (Exception e) {\n                    }\n                } else if (token.equals(\"must-revalidate\") || token.equals(\"proxy-revalidate\")) {\n                    mustRevalidate = true;\n                }\n            }\n        }\n\n        headerValue = headers.get(\"Expires\");\n        if (headerValue != null) {\n            serverExpires = parseDateAsEpoch(headerValue);\n        }\n\n        headerValue = headers.get(\"Last-Modified\");\n        if (headerValue != null) {\n            lastModified = parseDateAsEpoch(headerValue);\n        }\n\n        serverEtag = headers.get(\"ETag\");\n\n        // Cache-Control takes precedence over an Expires header, even if both exist and Expires\n        // is more restrictive.\n        if (hasCacheControl) {\n            softExpire = now + maxAge * 1000;\n            finalExpire = mustRevalidate\n                    ? softExpire\n                    : softExpire + staleWhileRevalidate * 1000;\n        } else if (serverDate > 0 && serverExpires >= serverDate) {\n            // Default semantic for Expire header in HTTP specification is softExpire.\n            softExpire = now + (serverExpires - serverDate);\n            finalExpire = softExpire;\n        }\n\n        Cache.Entry entry = new Cache.Entry();\n        entry.data = response.data;\n        entry.etag = serverEtag;\n        entry.softTtl = softExpire;\n        entry.ttl = finalExpire;\n        entry.serverDate = serverDate;\n        entry.lastModified = lastModified;\n        entry.responseHeaders = headers;\n\n        return entry;\n    }\n\n    /**\n     * Parse date in RFC1123 format, and return its value as epoch\n     */\n    public static long parseDateAsEpoch(String dateStr) {\n        try {\n            // Parse date in RFC1123 format if this header contains one\n            return DateUtils.parseDate(dateStr).getTime();\n        } catch (DateParseException e) {\n            // Date in invalid format, fallback to 0\n            return 0;\n        }\n    }\n\n    /**\n     * Retrieve a charset from headers\n     *\n     * @param headers An {@link Map} of headers\n     * @param defaultCharset Charset to return if none can be found\n     * @return Returns the charset specified in the Content-Type of this header,\n     * or the defaultCharset if none can be found.\n     */\n    public static String parseCharset(Map<String, String> headers, String defaultCharset) {\n        String contentType = headers.get(HTTP.CONTENT_TYPE);\n        if (contentType != null) {\n            String[] params = contentType.split(\";\");\n            for (int i = 1; i < params.length; i++) {\n                String[] pair = params[i].trim().split(\"=\");\n                if (pair.length == 2) {\n                    if (pair[0].equals(\"charset\")) {\n                        return pair[1];\n                    }\n                }\n            }\n        }\n\n        return defaultCharset;\n    }\n\n    /**\n     * Returns the charset specified in the Content-Type of this header,\n     * or the HTTP default (ISO-8859-1) if none can be found.\n     */\n    public static String parseCharset(Map<String, String> headers) {\n        return parseCharset(headers, HTTP.DEFAULT_CONTENT_CHARSET);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/HttpStack.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.AuthFailureError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\n\nimport org.apache.http.HttpResponse;\n\nimport java.io.IOException;\nimport java.util.Map;\n\n/**\n * An HTTP stack abstraction.\n */\npublic interface HttpStack {\n    /**\n     * Performs an HTTP request with the given parameters.\n     *\n     * <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise,\n     * and the Content-Type header is set to request.getPostBodyContentType().</p>\n     *\n     * @param request the request to perform\n     * @param additionalHeaders additional headers to be sent together with\n     *         {@link Request#getHeaders()}\n     * @return the HTTP response\n     */\n    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)\n        throws IOException, AuthFailureError;\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/HurlStack.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.AuthFailureError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\n\nimport org.apache.http.Header;\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.HttpStatus;\nimport org.apache.http.ProtocolVersion;\nimport org.apache.http.StatusLine;\nimport org.apache.http.entity.BasicHttpEntity;\nimport org.apache.http.message.BasicHeader;\nimport org.apache.http.message.BasicHttpResponse;\nimport org.apache.http.message.BasicStatusLine;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport javax.net.ssl.HttpsURLConnection;\nimport javax.net.ssl.SSLSocketFactory;\n\n/**\n * An {@link HttpStack} based on {@link HttpURLConnection}.\n */\npublic class HurlStack implements HttpStack {\n\n    private static final String HEADER_CONTENT_TYPE = \"Content-Type\";\n\n    /**\n     * An interface for transforming URLs before use.\n     */\n    public interface UrlRewriter {\n        /**\n         * Returns a URL to use instead of the provided one, or null to indicate\n         * this URL should not be used at all.\n         */\n        public String rewriteUrl(String originalUrl);\n    }\n\n    private final UrlRewriter mUrlRewriter;\n    private final SSLSocketFactory mSslSocketFactory;\n\n    public HurlStack() {\n        this(null);\n    }\n\n    /**\n     * @param urlRewriter Rewriter to use for request URLs\n     */\n    public HurlStack(UrlRewriter urlRewriter) {\n        this(urlRewriter, null);\n    }\n\n    /**\n     * @param urlRewriter Rewriter to use for request URLs\n     * @param sslSocketFactory SSL factory to use for HTTPS connections\n     */\n    public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {\n        mUrlRewriter = urlRewriter;\n        mSslSocketFactory = sslSocketFactory;\n    }\n\n    @Override\n    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)\n            throws IOException, AuthFailureError {\n        String url = request.getUrl();\n        HashMap<String, String> map = new HashMap<String, String>();\n        map.putAll(request.getHeaders());\n        map.putAll(additionalHeaders);\n        if (mUrlRewriter != null) {\n            String rewritten = mUrlRewriter.rewriteUrl(url);\n            if (rewritten == null) {\n                throw new IOException(\"URL blocked by rewriter: \" + url);\n            }\n            url = rewritten;\n        }\n        URL parsedUrl = new URL(url);\n        HttpURLConnection connection = openConnection(parsedUrl, request);\n        for (String headerName : map.keySet()) {\n            connection.addRequestProperty(headerName, map.get(headerName));\n        }\n        setConnectionParametersForRequest(connection, request);\n        // Initialize HttpResponse with data from the HttpURLConnection.\n        ProtocolVersion protocolVersion = new ProtocolVersion(\"HTTP\", 1, 1);\n        int responseCode = connection.getResponseCode();\n        if (responseCode == -1) {\n            // -1 is returned by getResponseCode() if the response code could not be retrieved.\n            // Signal to the caller that something was wrong with the connection.\n            throw new IOException(\"Could not retrieve response code from HttpUrlConnection.\");\n        }\n        StatusLine responseStatus = new BasicStatusLine(protocolVersion,\n                connection.getResponseCode(), connection.getResponseMessage());\n        BasicHttpResponse response = new BasicHttpResponse(responseStatus);\n        if (hasResponseBody(request.getMethod(), responseStatus.getStatusCode())) {\n            response.setEntity(entityFromConnection(connection));\n        }\n        for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {\n            if (header.getKey() != null) {\n                Header h = new BasicHeader(header.getKey(), header.getValue().get(0));\n                response.addHeader(h);\n            }\n        }\n        return response;\n    }\n\n    /**\n     * Checks if a response message contains a body.\n     * @see <a href=\"https://tools.ietf.org/html/rfc7230#section-3.3\">RFC 7230 section 3.3</a>\n     * @param requestMethod request method\n     * @param responseCode response status code\n     * @return whether the response has a body\n     */\n    private static boolean hasResponseBody(int requestMethod, int responseCode) {\n        return requestMethod != Request.Method.HEAD\n            && !(HttpStatus.SC_CONTINUE <= responseCode && responseCode < HttpStatus.SC_OK)\n            && responseCode != HttpStatus.SC_NO_CONTENT\n            && responseCode != HttpStatus.SC_NOT_MODIFIED;\n    }\n\n    /**\n     * Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}.\n     * @param connection\n     * @return an HttpEntity populated with data from <code>connection</code>.\n     */\n    private static HttpEntity entityFromConnection(HttpURLConnection connection) {\n        BasicHttpEntity entity = new BasicHttpEntity();\n        InputStream inputStream;\n        try {\n            inputStream = connection.getInputStream();\n        } catch (IOException ioe) {\n            inputStream = connection.getErrorStream();\n        }\n        entity.setContent(inputStream);\n        entity.setContentLength(connection.getContentLength());\n        entity.setContentEncoding(connection.getContentEncoding());\n        entity.setContentType(connection.getContentType());\n        return entity;\n    }\n\n    /**\n     * Create an {@link HttpURLConnection} for the specified {@code url}.\n     */\n    protected HttpURLConnection createConnection(URL url) throws IOException {\n        return (HttpURLConnection) url.openConnection();\n    }\n\n    /**\n     * Opens an {@link HttpURLConnection} with parameters.\n     * @param url\n     * @return an open connection\n     * @throws IOException\n     */\n    private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {\n        HttpURLConnection connection = createConnection(url);\n\n        int timeoutMs = request.getTimeoutMs();\n        connection.setConnectTimeout(timeoutMs);\n        connection.setReadTimeout(timeoutMs);\n        connection.setUseCaches(false);\n        connection.setDoInput(true);\n\n        // use caller-provided custom SslSocketFactory, if any, for HTTPS\n        if (\"https\".equals(url.getProtocol()) && mSslSocketFactory != null) {\n            ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);\n        }\n\n        return connection;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    /* package */ static void setConnectionParametersForRequest(HttpURLConnection connection,\n            Request<?> request) throws IOException, AuthFailureError {\n        switch (request.getMethod()) {\n            case Request.Method.DEPRECATED_GET_OR_POST:\n                // This is the deprecated way that needs to be handled for backwards compatibility.\n                // If the request's post body is null, then the assumption is that the request is\n                // GET.  Otherwise, it is assumed that the request is a POST.\n                byte[] postBody = request.getPostBody();\n                if (postBody != null) {\n                    // Prepare output. There is no need to set Content-Length explicitly,\n                    // since this is handled by HttpURLConnection using the size of the prepared\n                    // output stream.\n                    connection.setDoOutput(true);\n                    connection.setRequestMethod(\"POST\");\n                    connection.addRequestProperty(HEADER_CONTENT_TYPE,\n                            request.getPostBodyContentType());\n                    DataOutputStream out = new DataOutputStream(connection.getOutputStream());\n                    out.write(postBody);\n                    out.close();\n                }\n                break;\n            case Request.Method.GET:\n                // Not necessary to set the request method because connection defaults to GET but\n                // being explicit here.\n                connection.setRequestMethod(\"GET\");\n                break;\n            case Request.Method.DELETE:\n                connection.setRequestMethod(\"DELETE\");\n                break;\n            case Request.Method.POST:\n                connection.setRequestMethod(\"POST\");\n                addBodyIfExists(connection, request);\n                break;\n            case Request.Method.PUT:\n                connection.setRequestMethod(\"PUT\");\n                addBodyIfExists(connection, request);\n                break;\n            case Request.Method.HEAD:\n                connection.setRequestMethod(\"HEAD\");\n                break;\n            case Request.Method.OPTIONS:\n                connection.setRequestMethod(\"OPTIONS\");\n                break;\n            case Request.Method.TRACE:\n                connection.setRequestMethod(\"TRACE\");\n                break;\n            case Request.Method.PATCH:\n                connection.setRequestMethod(\"PATCH\");\n                addBodyIfExists(connection, request);\n                break;\n            default:\n                throw new IllegalStateException(\"Unknown method type.\");\n        }\n    }\n\n    private static void addBodyIfExists(HttpURLConnection connection, Request<?> request)\n            throws IOException, AuthFailureError {\n        byte[] body = request.getBody();\n        if (body != null) {\n            connection.setDoOutput(true);\n            connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getBodyContentType());\n            DataOutputStream out = new DataOutputStream(connection.getOutputStream());\n            out.write(body);\n            out.close();\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/ImageLoader.java",
    "content": "/**\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.Config;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.widget.ImageView;\nimport android.widget.ImageView.ScaleType;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.RequestQueue;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response.ErrorListener;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response.Listener;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyError;\n\nimport java.util.HashMap;\nimport java.util.LinkedList;\n\n/**\n * Helper that handles loading and caching images from remote URLs.\n *\n * The simple way to use this class is to call {@link ImageLoader#get(String, ImageListener)}\n * and to pass in the default image listener provided by\n * {@link ImageLoader#getImageListener(ImageView, int, int)}. Note that all function calls to\n * this class must be made from the main thead, and all responses will be delivered to the main\n * thread as well.\n */\npublic class ImageLoader {\n    /** RequestQueue for dispatching ImageRequests onto. */\n    private final RequestQueue mRequestQueue;\n\n    /** Amount of time to wait after first response arrives before delivering all responses. */\n    private int mBatchResponseDelayMs = 100;\n\n    /** The cache implementation to be used as an L1 cache before calling into volley. */\n    private final ImageCache mCache;\n\n    /**\n     * HashMap of Cache keys -> BatchedImageRequest used to track in-flight requests so\n     * that we can coalesce multiple requests to the same URL into a single network request.\n     */\n    private final HashMap<String, BatchedImageRequest> mInFlightRequests =\n            new HashMap<String, BatchedImageRequest>();\n\n    /** HashMap of the currently pending responses (waiting to be delivered). */\n    private final HashMap<String, BatchedImageRequest> mBatchedResponses =\n            new HashMap<String, BatchedImageRequest>();\n\n    /** Handler to the main thread. */\n    private final Handler mHandler = new Handler(Looper.getMainLooper());\n\n    /** Runnable for in-flight response delivery. */\n    private Runnable mRunnable;\n\n    /**\n     * Simple cache adapter interface. If provided to the ImageLoader, it\n     * will be used as an L1 cache before dispatch to Volley. Implementations\n     * must not block. Implementation with an LruCache is recommended.\n     */\n    public interface ImageCache {\n        public Bitmap getBitmap(String url);\n        public void putBitmap(String url, Bitmap bitmap);\n    }\n\n    /**\n     * Constructs a new ImageLoader.\n     * @param queue The RequestQueue to use for making image requests.\n     * @param imageCache The cache to use as an L1 cache.\n     */\n    public ImageLoader(RequestQueue queue, ImageCache imageCache) {\n        mRequestQueue = queue;\n        mCache = imageCache;\n    }\n\n    /**\n     * The default implementation of ImageListener which handles basic functionality\n     * of showing a default image until the network response is received, at which point\n     * it will switch to either the actual image or the error image.\n     * @param view The imageView that the listener is associated with.\n     * @param defaultImageResId Default image resource ID to use, or 0 if it doesn't exist.\n     * @param errorImageResId Error image resource ID to use, or 0 if it doesn't exist.\n     */\n    public static ImageListener getImageListener(final ImageView view,\n            final int defaultImageResId, final int errorImageResId) {\n        return new ImageListener() {\n            @Override\n            public void onErrorResponse(VolleyError error) {\n                if (errorImageResId != 0) {\n                    view.setImageResource(errorImageResId);\n                }\n            }\n\n            @Override\n            public void onResponse(ImageContainer response, boolean isImmediate) {\n                if (response.getBitmap() != null) {\n                    view.setImageBitmap(response.getBitmap());\n                } else if (defaultImageResId != 0) {\n                    view.setImageResource(defaultImageResId);\n                }\n            }\n        };\n    }\n\n    /**\n     * Interface for the response handlers on image requests.\n     *\n     * The call flow is this:\n     * 1. Upon being  attached to a request, onResponse(response, true) will\n     * be invoked to reflect any cached data that was already available. If the\n     * data was available, response.getBitmap() will be non-null.\n     *\n     * 2. After a network response returns, only one of the following cases will happen:\n     *   - onResponse(response, false) will be called if the image was loaded.\n     *   or\n     *   - onErrorResponse will be called if there was an error loading the image.\n     */\n    public interface ImageListener extends ErrorListener {\n        /**\n         * Listens for non-error changes to the loading of the image request.\n         *\n         * @param response Holds all information pertaining to the request, as well\n         * as the bitmap (if it is loaded).\n         * @param isImmediate True if this was called during ImageLoader.get() variants.\n         * This can be used to differentiate between a cached image loading and a network\n         * image loading in order to, for example, run an animation to fade in network loaded\n         * images.\n         */\n        public void onResponse(ImageContainer response, boolean isImmediate);\n    }\n\n    /**\n     * Checks if the item is available in the cache.\n     * @param requestUrl The url of the remote image\n     * @param maxWidth The maximum width of the returned image.\n     * @param maxHeight The maximum height of the returned image.\n     * @return True if the item exists in cache, false otherwise.\n     */\n    public boolean isCached(String requestUrl, int maxWidth, int maxHeight) {\n        return isCached(requestUrl, maxWidth, maxHeight, ScaleType.CENTER_INSIDE);\n    }\n\n    /**\n     * Checks if the item is available in the cache.\n     *\n     * @param requestUrl The url of the remote image\n     * @param maxWidth   The maximum width of the returned image.\n     * @param maxHeight  The maximum height of the returned image.\n     * @param scaleType  The scaleType of the imageView.\n     * @return True if the item exists in cache, false otherwise.\n     */\n    public boolean isCached(String requestUrl, int maxWidth, int maxHeight, ScaleType scaleType) {\n        throwIfNotOnMainThread();\n\n        String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType);\n        return mCache.getBitmap(cacheKey) != null;\n    }\n\n    /**\n     * Returns an ImageContainer for the requested URL.\n     *\n     * The ImageContainer will contain either the specified default bitmap or the loaded bitmap.\n     * If the default was returned, the {@link ImageLoader} will be invoked when the\n     * request is fulfilled.\n     *\n     * @param requestUrl The URL of the image to be loaded.\n     */\n    public ImageContainer get(String requestUrl, final ImageListener listener) {\n        return get(requestUrl, listener, 0, 0);\n    }\n\n    /**\n     * Equivalent to calling {@link #get(String, ImageListener, int, int, ScaleType)} with\n     * {@code Scaletype == ScaleType.CENTER_INSIDE}.\n     */\n    public ImageContainer get(String requestUrl, ImageListener imageListener,\n                              int maxWidth, int maxHeight) {\n        return get(requestUrl, imageListener, maxWidth, maxHeight, ScaleType.CENTER_INSIDE);\n    }\n\n    /**\n     * Issues a bitmap request with the given URL if that image is not available\n     * in the cache, and returns a bitmap container that contains all of the data\n     * relating to the request (as well as the default image if the requested\n     * image is not available).\n     * @param requestUrl The url of the remote image\n     * @param imageListener The listener to call when the remote image is loaded\n     * @param maxWidth The maximum width of the returned image.\n     * @param maxHeight The maximum height of the returned image.\n     * @param scaleType The ImageViews ScaleType used to calculate the needed image size.\n     * @return A container object that contains all of the properties of the request, as well as\n     *     the currently available image (default if remote is not loaded).\n     */\n    public ImageContainer get(String requestUrl, ImageListener imageListener,\n                              int maxWidth, int maxHeight, ScaleType scaleType) {\n\n        // only fulfill requests that were initiated from the main thread.\n        throwIfNotOnMainThread();\n\n        final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType);\n\n        // Try to look up the request in the cache of remote images.\n        Bitmap cachedBitmap = mCache.getBitmap(cacheKey);\n        if (cachedBitmap != null) {\n            // Return the cached bitmap.\n            ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);\n            imageListener.onResponse(container, true);\n            return container;\n        }\n\n        // The bitmap did not exist in the cache, fetch it!\n        ImageContainer imageContainer =\n                new ImageContainer(null, requestUrl, cacheKey, imageListener);\n\n        // Update the caller to let them know that they should use the default bitmap.\n        imageListener.onResponse(imageContainer, true);\n\n        // Check to see if a request is already in-flight.\n        BatchedImageRequest request = mInFlightRequests.get(cacheKey);\n        if (request != null) {\n            // If it is, add this request to the list of listeners.\n            request.addContainer(imageContainer);\n            return imageContainer;\n        }\n\n        // The request is not already in flight. Send the new request to the network and\n        // track it.\n        Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType,\n                cacheKey);\n\n        mRequestQueue.add(newRequest);\n        mInFlightRequests.put(cacheKey,\n                new BatchedImageRequest(newRequest, imageContainer));\n        return imageContainer;\n    }\n\n    protected Request<Bitmap> makeImageRequest(String requestUrl, int maxWidth, int maxHeight,\n                                               ScaleType scaleType, final String cacheKey) {\n        return new ImageRequest(requestUrl, new Listener<Bitmap>() {\n            @Override\n            public void onResponse(Bitmap response) {\n                onGetImageSuccess(cacheKey, response);\n            }\n        }, maxWidth, maxHeight, scaleType, Config.RGB_565, new ErrorListener() {\n            @Override\n            public void onErrorResponse(VolleyError error) {\n                onGetImageError(cacheKey, error);\n            }\n        });\n    }\n\n    /**\n     * Sets the amount of time to wait after the first response arrives before delivering all\n     * responses. Batching can be disabled entirely by passing in 0.\n     * @param newBatchedResponseDelayMs The time in milliseconds to wait.\n     */\n    public void setBatchedResponseDelay(int newBatchedResponseDelayMs) {\n        mBatchResponseDelayMs = newBatchedResponseDelayMs;\n    }\n\n    /**\n     * Handler for when an image was successfully loaded.\n     * @param cacheKey The cache key that is associated with the image request.\n     * @param response The bitmap that was returned from the network.\n     */\n    protected void onGetImageSuccess(String cacheKey, Bitmap response) {\n        // cache the image that was fetched.\n        mCache.putBitmap(cacheKey, response);\n\n        // remove the request from the list of in-flight requests.\n        BatchedImageRequest request = mInFlightRequests.remove(cacheKey);\n\n        if (request != null) {\n            // Update the response bitmap.\n            request.mResponseBitmap = response;\n\n            // Send the batched response\n            batchResponse(cacheKey, request);\n        }\n    }\n\n    /**\n     * Handler for when an image failed to load.\n     * @param cacheKey The cache key that is associated with the image request.\n     */\n    protected void onGetImageError(String cacheKey, VolleyError error) {\n        // Notify the requesters that something failed via a null result.\n        // Remove this request from the list of in-flight requests.\n        BatchedImageRequest request = mInFlightRequests.remove(cacheKey);\n\n        if (request != null) {\n            // Set the error for this request\n            request.setError(error);\n\n            // Send the batched response\n            batchResponse(cacheKey, request);\n        }\n    }\n\n    /**\n     * Container object for all of the data surrounding an image request.\n     */\n    public class ImageContainer {\n        /**\n         * The most relevant bitmap for the container. If the image was in cache, the\n         * Holder to use for the final bitmap (the one that pairs to the requested URL).\n         */\n        private Bitmap mBitmap;\n\n        private final ImageListener mListener;\n\n        /** The cache key that was associated with the request */\n        private final String mCacheKey;\n\n        /** The request URL that was specified */\n        private final String mRequestUrl;\n\n        /**\n         * Constructs a BitmapContainer object.\n         * @param bitmap The final bitmap (if it exists).\n         * @param requestUrl The requested URL for this container.\n         * @param cacheKey The cache key that identifies the requested URL for this container.\n         */\n        public ImageContainer(Bitmap bitmap, String requestUrl,\n                              String cacheKey, ImageListener listener) {\n            mBitmap = bitmap;\n            mRequestUrl = requestUrl;\n            mCacheKey = cacheKey;\n            mListener = listener;\n        }\n\n        /**\n         * Releases interest in the in-flight request (and cancels it if no one else is listening).\n         */\n        public void cancelRequest() {\n            if (mListener == null) {\n                return;\n            }\n\n            BatchedImageRequest request = mInFlightRequests.get(mCacheKey);\n            if (request != null) {\n                boolean canceled = request.removeContainerAndCancelIfNecessary(this);\n                if (canceled) {\n                    mInFlightRequests.remove(mCacheKey);\n                }\n            } else {\n                // check to see if it is already batched for delivery.\n                request = mBatchedResponses.get(mCacheKey);\n                if (request != null) {\n                    request.removeContainerAndCancelIfNecessary(this);\n                    if (request.mContainers.size() == 0) {\n                        mBatchedResponses.remove(mCacheKey);\n                    }\n                }\n            }\n        }\n\n        /**\n         * Returns the bitmap associated with the request URL if it has been loaded, null otherwise.\n         */\n        public Bitmap getBitmap() {\n            return mBitmap;\n        }\n\n        /**\n         * Returns the requested URL for this container.\n         */\n        public String getRequestUrl() {\n            return mRequestUrl;\n        }\n    }\n\n    /**\n     * Wrapper class used to map a Request to the set of active ImageContainer objects that are\n     * interested in its results.\n     */\n    private class BatchedImageRequest {\n        /** The request being tracked */\n        private final Request<?> mRequest;\n\n        /** The result of the request being tracked by this item */\n        private Bitmap mResponseBitmap;\n\n        /** Error if one occurred for this response */\n        private VolleyError mError;\n\n        /** List of all of the active ImageContainers that are interested in the request */\n        private final LinkedList<ImageContainer> mContainers = new LinkedList<ImageContainer>();\n\n        /**\n         * Constructs a new BatchedImageRequest object\n         * @param request The request being tracked\n         * @param container The ImageContainer of the person who initiated the request.\n         */\n        public BatchedImageRequest(Request<?> request, ImageContainer container) {\n            mRequest = request;\n            mContainers.add(container);\n        }\n\n        /**\n         * Set the error for this response\n         */\n        public void setError(VolleyError error) {\n            mError = error;\n        }\n\n        /**\n         * Get the error for this response\n         */\n        public VolleyError getError() {\n            return mError;\n        }\n\n        /**\n         * Adds another ImageContainer to the list of those interested in the results of\n         * the request.\n         */\n        public void addContainer(ImageContainer container) {\n            mContainers.add(container);\n        }\n\n        /**\n         * Detatches the bitmap container from the request and cancels the request if no one is\n         * left listening.\n         * @param container The container to remove from the list\n         * @return True if the request was canceled, false otherwise.\n         */\n        public boolean removeContainerAndCancelIfNecessary(ImageContainer container) {\n            mContainers.remove(container);\n            if (mContainers.size() == 0) {\n                mRequest.cancel();\n                return true;\n            }\n            return false;\n        }\n    }\n\n    /**\n     * Starts the runnable for batched delivery of responses if it is not already started.\n     * @param cacheKey The cacheKey of the response being delivered.\n     * @param request The BatchedImageRequest to be delivered.\n     */\n    private void batchResponse(String cacheKey, BatchedImageRequest request) {\n        mBatchedResponses.put(cacheKey, request);\n        // If we don't already have a batch delivery runnable in flight, make a new one.\n        // Note that this will be used to deliver responses to all callers in mBatchedResponses.\n        if (mRunnable == null) {\n            mRunnable = new Runnable() {\n                @Override\n                public void run() {\n                    for (BatchedImageRequest bir : mBatchedResponses.values()) {\n                        for (ImageContainer container : bir.mContainers) {\n                            // If one of the callers in the batched request canceled the request\n                            // after the response was received but before it was delivered,\n                            // skip them.\n                            if (container.mListener == null) {\n                                continue;\n                            }\n                            if (bir.getError() == null) {\n                                container.mBitmap = bir.mResponseBitmap;\n                                container.mListener.onResponse(container, false);\n                            } else {\n                                container.mListener.onErrorResponse(bir.getError());\n                            }\n                        }\n                    }\n                    mBatchedResponses.clear();\n                    mRunnable = null;\n                }\n\n            };\n            // Post the runnable.\n            mHandler.postDelayed(mRunnable, mBatchResponseDelayMs);\n        }\n    }\n\n    private void throwIfNotOnMainThread() {\n        if (Looper.myLooper() != Looper.getMainLooper()) {\n            throw new IllegalStateException(\"ImageLoader must be invoked from the main thread.\");\n        }\n    }\n    /**\n     * Creates a cache key for use with the L1 cache.\n     * @param url The URL of the request.\n     * @param maxWidth The max-width of the output.\n     * @param maxHeight The max-height of the output.\n     * @param scaleType The scaleType of the imageView.\n     */\n    private static String getCacheKey(String url, int maxWidth, int maxHeight, ScaleType scaleType) {\n        return new StringBuilder(url.length() + 12).append(\"#W\").append(maxWidth)\n                .append(\"#H\").append(maxHeight).append(\"#S\").append(scaleType.ordinal()).append(url)\n                .toString();\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/ImageRequest.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.Config;\nimport android.graphics.BitmapFactory;\nimport android.widget.ImageView.ScaleType;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.DefaultRetryPolicy;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NetworkResponse;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.ParseError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyLog;\n\n/**\n * A canned request for getting an image at a given URL and calling\n * back with a decoded Bitmap.\n */\npublic class ImageRequest extends Request<Bitmap> {\n    /** Socket timeout in milliseconds for image requests */\n    private static final int IMAGE_TIMEOUT_MS = 1000;\n\n    /** Default number of retries for image requests */\n    private static final int IMAGE_MAX_RETRIES = 2;\n\n    /** Default backoff multiplier for image requests */\n    private static final float IMAGE_BACKOFF_MULT = 2f;\n\n    private final Response.Listener<Bitmap> mListener;\n    private final Config mDecodeConfig;\n    private final int mMaxWidth;\n    private final int mMaxHeight;\n    private ScaleType mScaleType;\n\n    /** Decoding lock so that we don't decode more than one image at a time (to avoid OOM's) */\n    private static final Object sDecodeLock = new Object();\n\n    /**\n     * Creates a new image request, decoding to a maximum specified width and\n     * height. If both width and height are zero, the image will be decoded to\n     * its natural size. If one of the two is nonzero, that dimension will be\n     * clamped and the other one will be set to preserve the image's aspect\n     * ratio. If both width and height are nonzero, the image will be decoded to\n     * be fit in the rectangle of dimensions width x height while keeping its\n     * aspect ratio.\n     *\n     * @param url URL of the image\n     * @param listener Listener to receive the decoded bitmap\n     * @param maxWidth Maximum width to decode this bitmap to, or zero for none\n     * @param maxHeight Maximum height to decode this bitmap to, or zero for\n     *            none\n     * @param scaleType The ImageViews ScaleType used to calculate the needed image size.\n     * @param decodeConfig Format to decode the bitmap to\n     * @param errorListener Error listener, or null to ignore errors\n     */\n    public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,\n                        ScaleType scaleType, Config decodeConfig, Response.ErrorListener errorListener) {\n        super(Method.GET, url, errorListener); \n        setRetryPolicy(\n                new DefaultRetryPolicy(IMAGE_TIMEOUT_MS, IMAGE_MAX_RETRIES, IMAGE_BACKOFF_MULT));\n        mListener = listener;\n        mDecodeConfig = decodeConfig;\n        mMaxWidth = maxWidth;\n        mMaxHeight = maxHeight;\n        mScaleType = scaleType;\n    }\n\n    /**\n     * For API compatibility with the pre-ScaleType variant of the constructor. Equivalent to\n     * the normal constructor with {@code ScaleType.CENTER_INSIDE}.\n     */\n    @Deprecated\n    public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight,\n                        Config decodeConfig, Response.ErrorListener errorListener) {\n        this(url, listener, maxWidth, maxHeight,\n                ScaleType.CENTER_INSIDE, decodeConfig, errorListener);\n    }\n    @Override\n    public Priority getPriority() {\n        return Priority.LOW;\n    }\n\n    /**\n     * Scales one side of a rectangle to fit aspect ratio.\n     *\n     * @param maxPrimary Maximum size of the primary dimension (i.e. width for\n     *        max width), or zero to maintain aspect ratio with secondary\n     *        dimension\n     * @param maxSecondary Maximum size of the secondary dimension, or zero to\n     *        maintain aspect ratio with primary dimension\n     * @param actualPrimary Actual size of the primary dimension\n     * @param actualSecondary Actual size of the secondary dimension\n     * @param scaleType The ScaleType used to calculate the needed image size.\n     */\n    private static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary,\n            int actualSecondary, ScaleType scaleType) {\n\n        // If no dominant value at all, just return the actual.\n        if ((maxPrimary == 0) && (maxSecondary == 0)) {\n            return actualPrimary;\n        }\n\n        // If ScaleType.FIT_XY fill the whole rectangle, ignore ratio.\n        if (scaleType == ScaleType.FIT_XY) {\n            if (maxPrimary == 0) {\n                return actualPrimary;\n            }\n            return maxPrimary;\n        }\n\n        // If primary is unspecified, scale primary to match secondary's scaling ratio.\n        if (maxPrimary == 0) {\n            double ratio = (double) maxSecondary / (double) actualSecondary;\n            return (int) (actualPrimary * ratio);\n        }\n\n        if (maxSecondary == 0) {\n            return maxPrimary;\n        }\n\n        double ratio = (double) actualSecondary / (double) actualPrimary;\n        int resized = maxPrimary;\n\n        // If ScaleType.CENTER_CROP fill the whole rectangle, preserve aspect ratio.\n        if (scaleType == ScaleType.CENTER_CROP) {\n            if ((resized * ratio) < maxSecondary) {\n                resized = (int) (maxSecondary / ratio);\n            }\n            return resized;\n        }\n\n        if ((resized * ratio) > maxSecondary) {\n            resized = (int) (maxSecondary / ratio);\n        }\n        return resized;\n    }\n\n    @Override\n    protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {\n        // Serialize all decode on a global lock to reduce concurrent heap usage.\n        synchronized (sDecodeLock) {\n            try {\n                return doParse(response);\n            } catch (OutOfMemoryError e) {\n                VolleyLog.e(\"Caught OOM for %d byte image, url=%s\", response.data.length, getUrl());\n                return Response.error(new ParseError(e));\n            }\n        }\n    }\n\n    /**\n     * The real guts of parseNetworkResponse. Broken out for readability.\n     */\n    private Response<Bitmap> doParse(NetworkResponse response) {\n        byte[] data = response.data;\n        BitmapFactory.Options decodeOptions = new BitmapFactory.Options();\n        Bitmap bitmap = null;\n        if (mMaxWidth == 0 && mMaxHeight == 0) {\n            decodeOptions.inPreferredConfig = mDecodeConfig;\n            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);\n        } else {\n            // If we have to resize this image, first get the natural bounds.\n            decodeOptions.inJustDecodeBounds = true;\n            BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);\n            int actualWidth = decodeOptions.outWidth;\n            int actualHeight = decodeOptions.outHeight;\n\n            // Then compute the dimensions we would ideally like to decode to.\n            int desiredWidth = getResizedDimension(mMaxWidth, mMaxHeight,\n                    actualWidth, actualHeight, mScaleType);\n            int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth,\n                    actualHeight, actualWidth, mScaleType);\n\n            // Decode to the nearest power of two scaling factor.\n            decodeOptions.inJustDecodeBounds = false;\n            // TODO(ficus): Do we need this or is it okay since API 8 doesn't support it?\n            // decodeOptions.inPreferQualityOverSpeed = PREFER_QUALITY_OVER_SPEED;\n            decodeOptions.inSampleSize =\n                findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight);\n            Bitmap tempBitmap =\n                BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions);\n\n            // If necessary, scale down to the maximal acceptable size.\n            if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth ||\n                    tempBitmap.getHeight() > desiredHeight)) {\n                bitmap = Bitmap.createScaledBitmap(tempBitmap,\n                        desiredWidth, desiredHeight, true);\n                tempBitmap.recycle();\n            } else {\n                bitmap = tempBitmap;\n            }\n        }\n\n        if (bitmap == null) {\n            return Response.error(new ParseError(response));\n        } else {\n            return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response));\n        }\n    }\n\n    @Override\n    protected void deliverResponse(Bitmap response) {\n        mListener.onResponse(response);\n    }\n\n    /**\n     * Returns the largest power-of-two divisor for use in downscaling a bitmap\n     * that will not result in the scaling past the desired dimensions.\n     *\n     * @param actualWidth Actual width of the bitmap\n     * @param actualHeight Actual height of the bitmap\n     * @param desiredWidth Desired width of the bitmap\n     * @param desiredHeight Desired height of the bitmap\n     */\n    // Visible for testing.\n    static int findBestSampleSize(\n            int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {\n        double wr = (double) actualWidth / desiredWidth;\n        double hr = (double) actualHeight / desiredHeight;\n        double ratio = Math.min(wr, hr);\n        float n = 1.0f;\n        while ((n * 2) <= ratio) {\n            n *= 2;\n        }\n\n        return (int) n;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/JsonArrayRequest.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NetworkResponse;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.ParseError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response.ErrorListener;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response.Listener;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.UnsupportedEncodingException;\n\n/**\n * A request for retrieving a {@link JSONArray} response body at a given URL.\n */\npublic class JsonArrayRequest extends JsonRequest<JSONArray> {\n\n    /**\n     * Creates a new request.\n     * @param method the HTTP method to use\n     * @param url URL to fetch the JSON from\n     * @param requestBody A {@link String} to post with the request. Null is allowed and\n     *   indicates no parameters will be posted along with request.\n     * @param listener Listener to receive the JSON response\n     * @param errorListener Error listener, or null to ignore errors.\n     */\n    public JsonArrayRequest(int method, String url, String requestBody,\n                            Listener<JSONArray> listener, ErrorListener errorListener) {\n        super(method, url, requestBody, listener,\n                errorListener);\n    }\n\n    /**\n     * Creates a new request.\n     * @param url URL to fetch the JSON from\n     * @param listener Listener to receive the JSON response\n     * @param errorListener Error listener, or null to ignore errors.\n     */\n    public JsonArrayRequest(String url, Listener<JSONArray> listener, ErrorListener errorListener) {\n        super(Method.GET, url, null, listener, errorListener);\n    }\n\n    /**\n     * Creates a new request.\n     * @param method the HTTP method to use\n     * @param url URL to fetch the JSON from\n     * @param listener Listener to receive the JSON response\n     * @param errorListener Error listener, or null to ignore errors.\n     */\n    public JsonArrayRequest(int method, String url, Listener<JSONArray> listener, ErrorListener errorListener) {\n        super(method, url, null, listener, errorListener);\n    }\n\n    /**\n     * Creates a new request.\n     * @param method the HTTP method to use\n     * @param url URL to fetch the JSON from\n     * @param jsonRequest A {@link JSONArray} to post with the request. Null is allowed and\n     *   indicates no parameters will be posted along with request.\n     * @param listener Listener to receive the JSON response\n     * @param errorListener Error listener, or null to ignore errors.\n     */\n    public JsonArrayRequest(int method, String url, JSONArray jsonRequest,\n                            Listener<JSONArray> listener, ErrorListener errorListener) {\n        super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,\n                errorListener);\n    }\n\n    /**\n     * Creates a new request.\n     * @param method the HTTP method to use\n     * @param url URL to fetch the JSON from\n     * @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and\n     *   indicates no parameters will be posted along with request.\n     * @param listener Listener to receive the JSON response\n     * @param errorListener Error listener, or null to ignore errors.\n     */\n    public JsonArrayRequest(int method, String url, JSONObject jsonRequest,\n                            Listener<JSONArray> listener, ErrorListener errorListener) {\n        super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,\n                errorListener);\n    }\n\n    /**\n     * Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is\n     * <code>null</code>, <code>POST</code> otherwise.\n     *\n     * @see #JsonArrayRequest(int, String, JSONArray, Listener, ErrorListener)\n     */\n    public JsonArrayRequest(String url, JSONArray jsonRequest, Listener<JSONArray> listener,\n                            ErrorListener errorListener) {\n        this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest,\n                listener, errorListener);\n    }\n\n    /**\n     * Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is\n     * <code>null</code>, <code>POST</code> otherwise.\n     *\n     * @see #JsonArrayRequest(int, String, JSONObject, Listener, ErrorListener)\n     */\n    public JsonArrayRequest(String url, JSONObject jsonRequest, Listener<JSONArray> listener,\n                            ErrorListener errorListener) {\n        this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest,\n                listener, errorListener);\n    }\n\n    @Override\n    protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) {\n        try {\n            String jsonString = new String(response.data,\n                    HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));\n            return Response.success(new JSONArray(jsonString),\n                    HttpHeaderParser.parseCacheHeaders(response));\n        } catch (UnsupportedEncodingException e) {\n            return Response.error(new ParseError(e));\n        } catch (JSONException je) {\n            return Response.error(new ParseError(je));\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/JsonObjectRequest.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NetworkResponse;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.ParseError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.UnsupportedEncodingException;\n\n/**\n * A request for retrieving a {@link JSONObject} response body at a given URL, allowing for an\n * optional {@link JSONObject} to be passed in as part of the request body.\n */\npublic class JsonObjectRequest extends JsonRequest<JSONObject> {\n\n    /**\n     * Creates a new request.\n     * @param method the HTTP method to use\n     * @param url URL to fetch the JSON from\n     * @param requestBody A {@link String} to post with the request. Null is allowed and\n     *   indicates no parameters will be posted along with request.\n     * @param listener Listener to receive the JSON response\n     * @param errorListener Error listener, or null to ignore errors.\n     */\n    public JsonObjectRequest(int method, String url, String requestBody,\n                             Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {\n        super(method, url, requestBody, listener,\n                errorListener);\n    }\n\n    /**\n     * Creates a new request.\n     * @param url URL to fetch the JSON from\n     * @param listener Listener to receive the JSON response\n     * @param errorListener Error listener, or null to ignore errors.\n     */\n    public JsonObjectRequest(String url, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {\n        super(Method.GET, url, null, listener, errorListener);\n    }\n\n    /**\n     * Creates a new request.\n     * @param method the HTTP method to use\n     * @param url URL to fetch the JSON from\n     * @param listener Listener to receive the JSON response\n     * @param errorListener Error listener, or null to ignore errors.\n     */\n    public JsonObjectRequest(int method, String url, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {\n        super(method, url, null, listener, errorListener);\n    }\n\n    /**\n     * Creates a new request.\n     * @param method the HTTP method to use\n     * @param url URL to fetch the JSON from\n     * @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and\n     *   indicates no parameters will be posted along with request.\n     * @param listener Listener to receive the JSON response\n     * @param errorListener Error listener, or null to ignore errors.\n     */\n    public JsonObjectRequest(int method, String url, JSONObject jsonRequest,\n                             Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {\n        super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,\n                errorListener);\n    }\n\n    /**\n     * Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is\n     * <code>null</code>, <code>POST</code> otherwise.\n     *\n     * @see #JsonObjectRequest(int, String, JSONObject, Response.Listener, Response.ErrorListener)\n     */\n    public JsonObjectRequest(String url, JSONObject jsonRequest, Response.Listener<JSONObject> listener,\n                             Response.ErrorListener errorListener) {\n        this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest,\n                listener, errorListener);\n    }\n\n    @Override\n    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {\n        try {\n            String jsonString = new String(response.data,\n                    HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));\n            return Response.success(new JSONObject(jsonString),\n                    HttpHeaderParser.parseCacheHeaders(response));\n        } catch (UnsupportedEncodingException e) {\n            return Response.error(new ParseError(e));\n        } catch (JSONException je) {\n            return Response.error(new ParseError(je));\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/JsonRequest.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NetworkResponse;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response.ErrorListener;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response.Listener;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyLog;\n\nimport java.io.UnsupportedEncodingException;\n\n/**\n * A request for retrieving a T type response body at a given URL that also\n * optionally sends along a JSON body in the request specified.\n *\n * @param <T> JSON type of response expected\n */\npublic abstract class JsonRequest<T> extends Request<T> {\n    /** Default charset for JSON request. */\n    protected static final String PROTOCOL_CHARSET = \"utf-8\";\n\n    /** Content type for request. */\n    private static final String PROTOCOL_CONTENT_TYPE =\n        String.format(\"application/json; charset=%s\", PROTOCOL_CHARSET);\n\n    private Listener<T> mListener;\n    private final String mRequestBody;\n\n    /**\n     * Deprecated constructor for a JsonRequest which defaults to GET unless {@link #getPostBody()}\n     * or {@link #getPostParams()} is overridden (which defaults to POST).\n     *\n     * @deprecated Use {@link #JsonRequest(int, String, String, Listener, ErrorListener)}.\n     */\n    public JsonRequest(String url, String requestBody, Listener<T> listener,\n                       ErrorListener errorListener) {\n        this(Method.DEPRECATED_GET_OR_POST, url, requestBody, listener, errorListener);\n    }\n\n    public JsonRequest(int method, String url, String requestBody, Listener<T> listener,\n                       ErrorListener errorListener) {\n        super(method, url, errorListener);\n        mListener = listener;\n        mRequestBody = requestBody;\n    }\n\n    @Override\n    protected void onFinish() {\n        super.onFinish();\n        mListener = null;\n    }\n\n    @Override\n    protected void deliverResponse(T response) {\n        if (mListener != null) {\n            mListener.onResponse(response);\n        }\n    }\n\n    @Override\n    abstract protected Response<T> parseNetworkResponse(NetworkResponse response);\n\n    /**\n     * @deprecated Use {@link #getBodyContentType()}.\n     */\n    @Override\n    public String getPostBodyContentType() {\n        return getBodyContentType();\n    }\n\n    /**\n     * @deprecated Use {@link #getBody()}.\n     */\n    @Override\n    public byte[] getPostBody() {\n        return getBody();\n    }\n\n    @Override\n    public String getBodyContentType() {\n        return PROTOCOL_CONTENT_TYPE;\n    }\n\n    @Override\n    public byte[] getBody() {\n        try {\n            return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET);\n        } catch (UnsupportedEncodingException uee) {\n            VolleyLog.wtf(\"Unsupported Encoding while trying to get the bytes of %s using %s\",\n                    mRequestBody, PROTOCOL_CHARSET);\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/NetworkImageView.java",
    "content": "/**\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.view.ViewGroup.LayoutParams;\nimport android.widget.ImageView;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyError;\n\n/**\n * Handles fetching an image from a URL as well as the life-cycle of the\n * associated request.\n */\npublic class NetworkImageView extends ImageView {\n    /** The URL of the network image to load */\n    private String mUrl;\n\n    /**\n     * Resource ID of the image to be used as a placeholder until the network image is loaded.\n     */\n    private int mDefaultImageId;\n\n    /**\n     * Resource ID of the image to be used if the network response fails.\n     */\n    private int mErrorImageId;\n\n    /** Local copy of the ImageLoader. */\n    private ImageLoader mImageLoader;\n\n    /** Current ImageContainer. (either in-flight or finished) */\n    private ImageLoader.ImageContainer mImageContainer;\n\n    public NetworkImageView(Context context) {\n        this(context, null);\n    }\n\n    public NetworkImageView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public NetworkImageView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n    }\n\n    /**\n     * Sets URL of the image that should be loaded into this view. Note that calling this will\n     * immediately either set the cached image (if available) or the default image specified by\n     * {@link NetworkImageView#setDefaultImageResId(int)} on the view.\n     *\n     * NOTE: If applicable, {@link NetworkImageView#setDefaultImageResId(int)} and\n     * {@link NetworkImageView#setErrorImageResId(int)} should be called prior to calling\n     * this function.\n     *\n     * @param url The URL that should be loaded into this ImageView.\n     * @param imageLoader ImageLoader that will be used to make the request.\n     */\n    public void setImageUrl(String url, ImageLoader imageLoader) {\n        mUrl = url;\n        mImageLoader = imageLoader;\n        // The URL has potentially changed. See if we need to load it.\n        loadImageIfNecessary(false);\n    }\n    \n    /**\n     * Gets the URL of the image that should be loaded into this view, or null if no URL has been set.\n     * The image may or may not already be downloaded and set into the view.\n     * @return the URL of the image to be set into the view, or null.\n     */\n    public String getImageURL()\n    {\n    \treturn mUrl;\n    }\n\n    /**\n     * Sets the default image resource ID to be used for this view until the attempt to load it\n     * completes.\n     */\n    public void setDefaultImageResId(int defaultImage) {\n        mDefaultImageId = defaultImage;\n    }\n\n    /**\n     * Sets the error image resource ID to be used for this view in the event that the image\n     * requested fails to load.\n     */\n    public void setErrorImageResId(int errorImage) {\n        mErrorImageId = errorImage;\n    }\n\n    /**\n     * Loads the image for the view if it isn't already loaded.\n     * @param isInLayoutPass True if this was invoked from a layout pass, false otherwise.\n     */\n    void loadImageIfNecessary(final boolean isInLayoutPass) {\n        int width = getWidth();\n        int height = getHeight();\n        ScaleType scaleType = getScaleType();\n\n        boolean wrapWidth = false, wrapHeight = false;\n        if (getLayoutParams() != null) {\n            wrapWidth = getLayoutParams().width == LayoutParams.WRAP_CONTENT;\n            wrapHeight = getLayoutParams().height == LayoutParams.WRAP_CONTENT;\n        }\n\n        // if the view's bounds aren't known yet, and this is not a wrap-content/wrap-content\n        // view, hold off on loading the image.\n        boolean isFullyWrapContent = wrapWidth && wrapHeight;\n        if (width == 0 && height == 0 && !isFullyWrapContent) {\n            return;\n        }\n\n        // if the URL to be loaded in this view is empty, cancel any old requests and clear the\n        // currently loaded image.\n        if (TextUtils.isEmpty(mUrl)) {\n            if (mImageContainer != null) {\n                mImageContainer.cancelRequest();\n                mImageContainer = null;\n            }\n            setDefaultImageOrNull();\n            return;\n        }\n\n        // if there was an old request in this view, check if it needs to be canceled.\n        if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {\n            if (mImageContainer.getRequestUrl().equals(mUrl)) {\n                // if the request is from the same URL, return.\n                return;\n            } else {\n                // if there is a pre-existing request, cancel it if it's fetching a different URL.\n                mImageContainer.cancelRequest();\n                setDefaultImageOrNull();\n            }\n        }\n\n        // Calculate the max image width / height to use while ignoring WRAP_CONTENT dimens.\n        int maxWidth = wrapWidth ? 0 : width;\n        int maxHeight = wrapHeight ? 0 : height;\n\n        // The pre-existing content of this view didn't match the current URL. Load the new image\n        // from the network.\n        ImageLoader.ImageContainer newContainer = mImageLoader.get(mUrl,\n                new ImageLoader.ImageListener() {\n                    @Override\n                    public void onErrorResponse(VolleyError error) {\n                        if (mErrorImageId != 0) {\n                            setImageResource(mErrorImageId);\n                        }\n                    }\n\n                    @Override\n                    public void onResponse(final ImageLoader.ImageContainer response, boolean isImmediate) {\n                        // If this was an immediate response that was delivered inside of a layout\n                        // pass do not set the image immediately as it will trigger a requestLayout\n                        // inside of a layout. Instead, defer setting the image by posting back to\n                        // the main thread.\n                        if (isImmediate && isInLayoutPass) {\n                            post(new Runnable() {\n                                @Override\n                                public void run() {\n                                    onResponse(response, false);\n                                }\n                            });\n                            return;\n                        }\n\n                        if (response.getBitmap() != null) {\n                            setImageBitmap(response.getBitmap());\n                        } else if (mDefaultImageId != 0) {\n                            setImageResource(mDefaultImageId);\n                        }\n                    }\n                }, maxWidth, maxHeight, scaleType);\n\n        // update the ImageContainer to be the new bitmap container.\n        mImageContainer = newContainer;\n    }\n\n    private void setDefaultImageOrNull() {\n        if(mDefaultImageId != 0) {\n            setImageResource(mDefaultImageId);\n        }\n        else {\n            setImageBitmap(null);\n        }\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\n        super.onLayout(changed, left, top, right, bottom);\n        loadImageIfNecessary(true);\n    }\n\n    @Override\n    protected void onDetachedFromWindow() {\n        if (mImageContainer != null) {\n            // If the view was bound to an image request, cancel it and clear\n            // out the image from the view.\n            mImageContainer.cancelRequest();\n            setImageBitmap(null);\n            // also clear out the container so we can reload the image if necessary.\n            mImageContainer = null;\n        }\n        super.onDetachedFromWindow();\n    }\n\n    @Override\n    protected void drawableStateChanged() {\n        super.drawableStateChanged();\n        invalidate();\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/NoCache.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Cache;\n\n/**\n * A cache that doesn't.\n */\npublic class NoCache implements Cache {\n    @Override\n    public void clear() {\n    }\n\n    @Override\n    public Entry get(String key) {\n        return null;\n    }\n\n    @Override\n    public void put(String key, Entry entry) {\n    }\n\n    @Override\n    public void invalidate(String key, boolean fullExpire) {\n    }\n\n    @Override\n    public void remove(String key) {\n    }\n\n    @Override\n    public void initialize() {\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/PoolingByteArrayOutputStream.java",
    "content": "/*\n * Copyright (C) 2012 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\n/**\n * A variation of {@link ByteArrayOutputStream} that uses a pool of byte[] buffers instead\n * of always allocating them fresh, saving on heap churn.\n */\npublic class PoolingByteArrayOutputStream extends ByteArrayOutputStream {\n    /**\n     * If the {@link #PoolingByteArrayOutputStream(ByteArrayPool)} constructor is called, this is\n     * the default size to which the underlying byte array is initialized.\n     */\n    private static final int DEFAULT_SIZE = 256;\n\n    private final ByteArrayPool mPool;\n\n    /**\n     * Constructs a new PoolingByteArrayOutputStream with a default size. If more bytes are written\n     * to this instance, the underlying byte array will expand.\n     */\n    public PoolingByteArrayOutputStream(ByteArrayPool pool) {\n        this(pool, DEFAULT_SIZE);\n    }\n\n    /**\n     * Constructs a new {@code ByteArrayOutputStream} with a default size of {@code size} bytes. If\n     * more than {@code size} bytes are written to this instance, the underlying byte array will\n     * expand.\n     *\n     * @param size initial size for the underlying byte array. The value will be pinned to a default\n     *        minimum size.\n     */\n    public PoolingByteArrayOutputStream(ByteArrayPool pool, int size) {\n        mPool = pool;\n        buf = mPool.getBuf(Math.max(size, DEFAULT_SIZE));\n    }\n\n    @Override\n    public void close() throws IOException {\n        mPool.returnBuf(buf);\n        buf = null;\n        super.close();\n    }\n\n    @Override\n    public void finalize() {\n        mPool.returnBuf(buf);\n    }\n\n    /**\n     * Ensures there is enough space in the buffer for the given number of additional bytes.\n     */\n    private void expand(int i) {\n        /* Can the buffer handle @i more bytes, if not expand it */\n        if (count + i <= buf.length) {\n            return;\n        }\n        byte[] newbuf = mPool.getBuf((count + i) * 2);\n        System.arraycopy(buf, 0, newbuf, 0, count);\n        mPool.returnBuf(buf);\n        buf = newbuf;\n    }\n\n    @Override\n    public synchronized void write(byte[] buffer, int offset, int len) {\n        expand(len);\n        super.write(buffer, offset, len);\n    }\n\n    @Override\n    public synchronized void write(int oneByte) {\n        expand(1);\n        super.write(oneByte);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/RequestFuture.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyError;\n\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\n/**\n * A Future that represents a Volley request.\n *\n * Used by providing as your response and error listeners. For example:\n * <pre>\n * RequestFuture&lt;JSONObject&gt; future = RequestFuture.newFuture();\n * MyRequest request = new MyRequest(URL, future, future);\n *\n * // If you want to be able to cancel the request:\n * future.setRequest(requestQueue.add(request));\n *\n * // Otherwise:\n * requestQueue.add(request);\n *\n * try {\n *   JSONObject response = future.get();\n *   // do something with response\n * } catch (InterruptedException e) {\n *   // handle the error\n * } catch (ExecutionException e) {\n *   // handle the error\n * }\n * </pre>\n *\n * @param <T> The type of parsed response this future expects.\n */\npublic class RequestFuture<T> implements Future<T>, Response.Listener<T>,\n       Response.ErrorListener {\n    private Request<?> mRequest;\n    private boolean mResultReceived = false;\n    private T mResult;\n    private VolleyError mException;\n\n    public static <E> RequestFuture<E> newFuture() {\n        return new RequestFuture<E>();\n    }\n\n    private RequestFuture() {}\n\n    public void setRequest(Request<?> request) {\n        mRequest = request;\n    }\n\n    @Override\n    public synchronized boolean cancel(boolean mayInterruptIfRunning) {\n        if (mRequest == null) {\n            return false;\n        }\n\n        if (!isDone()) {\n            mRequest.cancel();\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    @Override\n    public T get() throws InterruptedException, ExecutionException {\n        try {\n            return doGet(null);\n        } catch (TimeoutException e) {\n            throw new AssertionError(e);\n        }\n    }\n\n    @Override\n    public T get(long timeout, TimeUnit unit)\n            throws InterruptedException, ExecutionException, TimeoutException {\n        return doGet(TimeUnit.MILLISECONDS.convert(timeout, unit));\n    }\n\n    private synchronized T doGet(Long timeoutMs)\n            throws InterruptedException, ExecutionException, TimeoutException {\n        if (mException != null) {\n            throw new ExecutionException(mException);\n        }\n\n        if (mResultReceived) {\n            return mResult;\n        }\n\n        if (timeoutMs == null) {\n            wait(0);\n        } else if (timeoutMs > 0) {\n            wait(timeoutMs);\n        }\n\n        if (mException != null) {\n            throw new ExecutionException(mException);\n        }\n\n        if (!mResultReceived) {\n            throw new TimeoutException();\n        }\n\n        return mResult;\n    }\n\n    @Override\n    public boolean isCancelled() {\n        if (mRequest == null) {\n            return false;\n        }\n        return mRequest.isCanceled();\n    }\n\n    @Override\n    public synchronized boolean isDone() {\n        return mResultReceived || mException != null || isCancelled();\n    }\n\n    @Override\n    public synchronized void onResponse(T response) {\n        mResultReceived = true;\n        mResult = response;\n        notifyAll();\n    }\n\n    @Override\n    public synchronized void onErrorResponse(VolleyError error) {\n        mException = error;\n        notifyAll();\n    }\n}\n\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/StringRequest.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NetworkResponse;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response;\n\nimport java.io.UnsupportedEncodingException;\n\n/**\n * A canned request for retrieving the response body at a given URL as a String.\n */\npublic class StringRequest extends Request<String> {\n    private Response.Listener<String> mListener;\n\n    /**\n     * Creates a new request with the given method.\n     *\n     * @param method the request {@link Method} to use\n     * @param url URL to fetch the string at\n     * @param listener Listener to receive the String response\n     * @param errorListener Error listener, or null to ignore errors\n     */\n    public StringRequest(int method, String url, Response.Listener<String> listener,\n                         Response.ErrorListener errorListener) {\n        super(method, url, errorListener);\n        mListener = listener;\n    }\n\n    /**\n     * Creates a new GET request.\n     *\n     * @param get\n     * @param url URL to fetch the string at\n     * @param b\n     * @param listener Listener to receive the String response\n     * @param errorListener Error listener, or null to ignore errors\n     */\n    public StringRequest(int get, String url, boolean b, Response.Listener<String> listener, Response.ErrorListener errorListener) {\n        this(Method.GET, url, listener, errorListener);\n    }\n\n    @Override\n    protected void onFinish() {\n        super.onFinish();\n        mListener = null;\n    }\n\n    @Override\n    protected void deliverResponse(String response) {\n        if (mListener != null) {\n            mListener.onResponse(response);\n        }\n    }\n\n    @Override\n    protected Response<String> parseNetworkResponse(NetworkResponse response) {\n        String parsed;\n        try {\n            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));\n        } catch (UnsupportedEncodingException e) {\n            parsed = new String(response.data);\n        }\n        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/google/volley/toolbox/Volley.java",
    "content": "/*\n * Copyright (C) 2012 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox;\n\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager.NameNotFoundException;\nimport android.net.http.AndroidHttpClient;\nimport android.os.Build;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Network;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.RequestQueue;\n\nimport java.io.File;\n\npublic class Volley {\n\n    /** Default on-disk cache directory. */\n    private static final String DEFAULT_CACHE_DIR = \"volley\";\n\n    /**\n     * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.\n     * You may set a maximum size of the disk cache in bytes.\n     *\n     * @param context A {@link Context} to use for creating the cache dir.\n     * @param stack An {@link HttpStack} to use for the network, or null for default.\n     * @param maxDiskCacheBytes the maximum size of the disk cache, in bytes. Use -1 for default size.\n     * @return A started {@link RequestQueue} instance.\n     */\n    public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {\n        File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);\n\n        String userAgent = \"volley/0\";\n        try {\n            String packageName = context.getPackageName();\n            PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);\n            userAgent = packageName + \"/\" + info.versionCode;\n        } catch (NameNotFoundException e) {\n        }\n\n        if (stack == null) {\n            if (Build.VERSION.SDK_INT >= 9) {\n                stack = new HurlStack();\n            } else {\n                // Prior to Gingerbread, HttpUrlConnection was unreliable.\n                // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html\n                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));\n            }\n        }\n\n        Network network = new BasicNetwork(stack);\n        \n        RequestQueue queue;\n        if (maxDiskCacheBytes <= -1)\n        {\n        \t// No maximum size specified\n        \tqueue = new RequestQueue(new DiskBasedCache(cacheDir), network);\n        }\n        else\n        {\n        \t// Disk cache size specified\n        \tqueue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);\n        }\n\n        queue.start();\n\n        return queue;\n    }\n    \n    /**\n     * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.\n     * You may set a maximum size of the disk cache in bytes.\n     *\n     * @param context A {@link Context} to use for creating the cache dir.\n     * @param maxDiskCacheBytes the maximum size of the disk cache, in bytes. Use -1 for default size.\n     * @return A started {@link RequestQueue} instance.\n     */\n    public static RequestQueue newRequestQueue(Context context, int maxDiskCacheBytes) {\n        return newRequestQueue(context, null, maxDiskCacheBytes);\n    }\n    \n    /**\n     * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.\n     *\n     * @param context A {@link Context} to use for creating the cache dir.\n     * @param stack An {@link HttpStack} to use for the network, or null for default.\n     * @return A started {@link RequestQueue} instance.\n     */\n    public static RequestQueue newRequestQueue(Context context, HttpStack stack)\n    {\n    \treturn newRequestQueue(context, stack, -1);\n    }\n    \n    /**\n     * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.\n     *\n     * @param context A {@link Context} to use for creating the cache dir.\n     * @return A started {@link RequestQueue} instance.\n     */\n    public static RequestQueue newRequestQueue(Context context) {\n        return newRequestQueue(context, null);\n    }\n\n}\n\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/AndroidLogAdapter.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\npublic class AndroidLogAdapter implements LogAdapter {\n\n  private final FormatStrategy formatStrategy;\n\n  public AndroidLogAdapter() {\n    this.formatStrategy = PrettyFormatStrategy.newBuilder().build();\n  }\n\n  public AndroidLogAdapter(FormatStrategy formatStrategy) {\n    this.formatStrategy = formatStrategy;\n  }\n\n  @Override\n  public boolean isLoggable(int priority, String tag) {\n    return true;\n  }\n\n  @Override\n  public void log(int priority, String tag, String message) {\n    formatStrategy.log(priority, tag, message);\n  }\n\n}"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/CsvFormatStrategy.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\nimport android.os.Environment;\nimport android.os.Handler;\nimport android.os.HandlerThread;\n\nimport java.io.File;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\n\n/**\n * CSV formatted file logging for Android.\n * Writes to CSV the following data:\n * epoch timestamp, ISO8601 timestamp (human-readable), log level, tag, log message.\n */\npublic class CsvFormatStrategy implements FormatStrategy {\n\n  private static final String NEW_LINE = System.getProperty(\"line.separator\");\n  private static final String NEW_LINE_REPLACEMENT = \" <br> \";\n  private static final String SEPARATOR = \",\";\n\n  private final Date date;\n  private final SimpleDateFormat dateFormat;\n  private final LogStrategy logStrategy;\n  private final String tag;\n\n  private CsvFormatStrategy(Builder builder) {\n    date = builder.date;\n    dateFormat = builder.dateFormat;\n    logStrategy = builder.logStrategy;\n    tag = builder.tag;\n  }\n\n  public static Builder newBuilder() {\n    return new Builder();\n  }\n\n  @Override\n  public void log(int priority, String onceOnlyTag, String message) {\n    String tag = formatTag(onceOnlyTag);\n\n    date.setTime(System.currentTimeMillis());\n\n    StringBuilder builder = new StringBuilder();\n\n    // machine-readable date/time\n    builder.append(Long.toString(date.getTime()));\n\n    // human-readable date/time\n    builder.append(SEPARATOR);\n    builder.append(dateFormat.format(date));\n\n    // level\n    builder.append(SEPARATOR);\n    builder.append(Utils.logLevel(priority));\n\n    // tag\n    builder.append(SEPARATOR);\n    builder.append(tag);\n\n    // message\n    if (message.contains(NEW_LINE)) {\n      // a new line would break the CSV format, so we replace it here\n      message = message.replaceAll(NEW_LINE, NEW_LINE_REPLACEMENT);\n    }\n    builder.append(SEPARATOR);\n    builder.append(message);\n\n    // new line\n    builder.append(NEW_LINE);\n\n    logStrategy.log(priority, tag, builder.toString());\n  }\n\n  private String formatTag(String tag) {\n    if (!Utils.isEmpty(tag) && !Utils.equals(this.tag, tag)) {\n      return this.tag + \"-\" + tag;\n    }\n    return this.tag;\n  }\n\n  public static final class Builder {\n    private static final int MAX_BYTES = 500 * 1024; // 500K averages to a 4000 lines per file\n\n    Date date;\n    SimpleDateFormat dateFormat;\n    LogStrategy logStrategy;\n    String tag = \"PRETTY_LOGGER\";\n\n    private Builder() {\n    }\n\n    public Builder date(Date val) {\n      date = val;\n      return this;\n    }\n\n    public Builder dateFormat(SimpleDateFormat val) {\n      dateFormat = val;\n      return this;\n    }\n\n    public Builder logStrategy(LogStrategy val) {\n      logStrategy = val;\n      return this;\n    }\n\n    public Builder tag(String tag) {\n      this.tag = tag;\n      return this;\n    }\n\n    public CsvFormatStrategy build() {\n      if (date == null) {\n        date = new Date();\n      }\n      if (dateFormat == null) {\n        dateFormat = new SimpleDateFormat(\"yyyy.MM.dd HH:mm:ss.SSS\", Locale.UK);\n      }\n      if (logStrategy == null) {\n        String diskPath = Environment.getExternalStorageDirectory().getAbsolutePath();\n        String folder = diskPath + File.separatorChar + \"logger\";\n\n        HandlerThread ht = new HandlerThread(\"AndroidFileLogger.\" + folder);\n        ht.start();\n        Handler handler = new DiskLogStrategy.WriteHandler(ht.getLooper(), folder, MAX_BYTES);\n        logStrategy = new DiskLogStrategy(handler);\n      }\n      return new CsvFormatStrategy(this);\n    }\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/DiskLogAdapter.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\npublic class DiskLogAdapter implements LogAdapter {\n\n  private final FormatStrategy formatStrategy;\n\n  public DiskLogAdapter() {\n    formatStrategy = CsvFormatStrategy.newBuilder().build();\n  }\n\n  public DiskLogAdapter(FormatStrategy formatStrategy) {\n    this.formatStrategy = formatStrategy;\n  }\n\n  @Override\n  public boolean isLoggable(int priority, String tag) {\n    return true;\n  }\n\n  @Override\n  public void log(int priority, String tag, String message) {\n    formatStrategy.log(priority, tag, message);\n  }\n}"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/DiskLogStrategy.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Message;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\n\n/**\n * Abstract class that takes care of background threading the file log operation on Android.\n * implementing classes are free to directly perform I/O operations there.\n */\npublic class DiskLogStrategy implements LogStrategy {\n\n  private final Handler handler;\n\n  public DiskLogStrategy(Handler handler) {\n    this.handler = handler;\n  }\n\n  @Override\n  public void log(int level, String tag, String message) {\n    // do nothing on the calling thread, simply pass the tag/msg to the background thread\n    handler.sendMessage(handler.obtainMessage(level, message));\n  }\n\n  static class WriteHandler extends Handler {\n\n    private final String folder;\n    private final int maxFileSize;\n\n    WriteHandler(Looper looper, String folder, int maxFileSize) {\n      super(looper);\n      this.folder = folder;\n      this.maxFileSize = maxFileSize;\n    }\n\n    @SuppressWarnings(\"checkstyle:emptyblock\")\n    @Override\n    public void handleMessage(Message msg) {\n      String content = (String) msg.obj;\n\n      FileWriter fileWriter = null;\n      File logFile = getLogFile(folder, \"logs\");\n\n      try {\n        fileWriter = new FileWriter(logFile, true);\n\n        writeLog(fileWriter, content);\n\n        fileWriter.flush();\n        fileWriter.close();\n      } catch (IOException e) {\n        if (fileWriter != null) {\n          try {\n            fileWriter.flush();\n            fileWriter.close();\n          } catch (IOException e1) { /* fail silently */ }\n        }\n      }\n    }\n\n    /**\n     * This is always called on a single background thread.\n     * Implementing classes must ONLY write to the fileWriter and nothing more.\n     * The abstract class takes care of everything else including close the stream and catching IOException\n     *\n     * @param fileWriter an instance of FileWriter already initialised to the correct file\n     */\n    private void writeLog(FileWriter fileWriter, String content) throws IOException {\n      fileWriter.append(content);\n    }\n\n    private File getLogFile(String folderName, String fileName) {\n\n      File folder = new File(folderName);\n      if (!folder.exists()) {\n        //TODO: What if folder is not created, what happens then?\n        folder.mkdirs();\n      }\n\n      int newFileCount = 0;\n      File newFile;\n      File existingFile = null;\n\n      newFile = new File(folder, String.format(\"%s_%s.csv\", fileName, newFileCount));\n      while (newFile.exists()) {\n        existingFile = newFile;\n        newFileCount++;\n        newFile = new File(folder, String.format(\"%s_%s.csv\", fileName, newFileCount));\n      }\n\n      if (existingFile != null) {\n        if (existingFile.length() >= maxFileSize) {\n          return newFile;\n        }\n        return existingFile;\n      }\n\n      return newFile;\n    }\n  }\n}"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/FormatStrategy.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\npublic interface FormatStrategy {\n\n  void log(int priority, String tag, String message);\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/LogAdapter.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\npublic interface LogAdapter {\n\n  boolean isLoggable(int priority, String tag);\n\n  void log(int priority, String tag, String message);\n}"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/LogStrategy.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\npublic interface LogStrategy {\n\n  void log(int priority, String tag, String message);\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/LogcatLogStrategy.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\nimport android.util.Log;\n\npublic class LogcatLogStrategy implements LogStrategy {\n\n  @Override\n  public void log(int priority, String tag, String message) {\n    Log.println(priority, tag, message);\n  }\n\n}"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/Logger.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\n/**\n * But more pretty, simple and powerful\n */\npublic final class Logger {\n\n  public static final int VERBOSE = 2;\n  public static final int DEBUG = 3;\n  public static final int INFO = 4;\n  public static final int WARN = 5;\n  public static final int ERROR = 6;\n  public static final int ASSERT = 7;\n\n  private static Printer printer = new LoggerPrinter();\n\n  private Logger() {\n    //no instance\n  }\n\n  public static void printer(Printer printer) {\n    Logger.printer = printer;\n  }\n\n  public static void addLogAdapter(LogAdapter adapter) {\n    printer.addAdapter(adapter);\n  }\n\n  public static void clearLogAdapters() {\n    printer.clearLogAdapters();\n  }\n\n  /**\n   * Given tag will be used as tag only once for this method call regardless of the tag that's been\n   * set during initialization. After this invocation, the general tag that's been set will\n   * be used for the subsequent log calls\n   */\n  public static Printer t(String tag) {\n    return printer.t(tag);\n  }\n\n  /**\n   * General log function that accepts all configurations as parameter\n   */\n  public static void log(int priority, String tag, String message, Throwable throwable) {\n    printer.log(priority, tag, message, throwable);\n  }\n\n  public static void d(String message, Object... args) {\n    printer.d(message, args);\n  }\n\n  public static void d(Object object) {\n    printer.d(object);\n  }\n\n  public static void e(String message, Object... args) {\n    printer.e(null, message, args);\n  }\n\n  public static void e(Throwable throwable, String message, Object... args) {\n    printer.e(throwable, message, args);\n  }\n\n  public static void i(String message, Object... args) {\n    printer.i(message, args);\n  }\n\n  public static void v(String message, Object... args) {\n    printer.v(message, args);\n  }\n\n  public static void w(String message, Object... args) {\n    printer.w(message, args);\n  }\n\n  /**\n   * Tip: Use this for exceptional situations to log\n   * ie: Unexpected errors etc\n   */\n  public static void wtf(String message, Object... args) {\n    printer.wtf(message, args);\n  }\n\n  /**\n   * Formats the given json content and print it\n   */\n  public static void json(String json) {\n    printer.json(json);\n  }\n\n  /**\n   * Formats the given xml content and print it\n   */\n  public static void xml(String xml) {\n    printer.xml(xml);\n  }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/LoggerPrinter.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.xml.transform.OutputKeys;\nimport javax.xml.transform.Source;\nimport javax.xml.transform.Transformer;\nimport javax.xml.transform.TransformerException;\nimport javax.xml.transform.TransformerFactory;\nimport javax.xml.transform.stream.StreamResult;\nimport javax.xml.transform.stream.StreamSource;\n\nclass LoggerPrinter implements Printer {\n\n  /**\n   * It is used for json pretty print\n   */\n  private static final int JSON_INDENT = 2;\n\n  /**\n   * Provides one-time used tag for the log message\n   */\n  private final ThreadLocal<String> localTag = new ThreadLocal<>();\n\n  private final List<LogAdapter> logAdapters = new ArrayList<>();\n\n  @Override\n  public Printer t(String tag) {\n    if (tag != null) {\n      localTag.set(tag);\n    }\n    return this;\n  }\n\n  @Override\n  public void d(String message, Object... args) {\n    log(Logger.DEBUG, null, message, args);\n  }\n\n  @Override\n  public void d(Object object) {\n    log(Logger.DEBUG, null, Utils.toString(object));\n  }\n\n  @Override\n  public void e(String message, Object... args) {\n    e(null, message, args);\n  }\n\n  @Override\n  public void e(Throwable throwable, String message, Object... args) {\n    log(Logger.ERROR, throwable, message, args);\n  }\n\n  @Override\n  public void w(String message, Object... args) {\n    log(Logger.WARN, null, message, args);\n  }\n\n  @Override\n  public void i(String message, Object... args) {\n    log(Logger.INFO, null, message, args);\n  }\n\n  @Override\n  public void v(String message, Object... args) {\n    log(Logger.VERBOSE, null, message, args);\n  }\n\n  @Override\n  public void wtf(String message, Object... args) {\n    log(Logger.ASSERT, null, message, args);\n  }\n\n  @Override\n  public void json(String json) {\n    if (Utils.isEmpty(json)) {\n      d(\"Empty/Null json content\");\n      return;\n    }\n    try {\n      json = json.trim();\n      if (json.startsWith(\"{\")) {\n        JSONObject jsonObject = new JSONObject(json);\n        String message = jsonObject.toString(JSON_INDENT);\n        d(message);\n        return;\n      }\n      if (json.startsWith(\"[\")) {\n        JSONArray jsonArray = new JSONArray(json);\n        String message = jsonArray.toString(JSON_INDENT);\n        d(message);\n        return;\n      }\n      e(\"Invalid Json\");\n    } catch (JSONException e) {\n      e(\"Invalid Json\");\n    }\n  }\n\n  @Override\n  public void xml(String xml) {\n    if (Utils.isEmpty(xml)) {\n      d(\"Empty/Null xml content\");\n      return;\n    }\n    try {\n      Source xmlInput = new StreamSource(new StringReader(xml));\n      StreamResult xmlOutput = new StreamResult(new StringWriter());\n      Transformer transformer = TransformerFactory.newInstance().newTransformer();\n      transformer.setOutputProperty(OutputKeys.INDENT, \"yes\");\n      transformer.setOutputProperty(\"{http://xml.apache.org/xslt}indent-amount\", \"2\");\n      transformer.transform(xmlInput, xmlOutput);\n      d(xmlOutput.getWriter().toString().replaceFirst(\">\", \">\\n\"));\n    } catch (TransformerException e) {\n      e(\"Invalid xml\");\n    }\n  }\n\n  @Override\n  public synchronized void log(int priority, String tag, String message, Throwable throwable) {\n    if (throwable != null && message != null) {\n      message += \" : \" + Utils.getStackTraceString(throwable);\n    }\n    if (throwable != null && message == null) {\n      message = Utils.getStackTraceString(throwable);\n    }\n    if (Utils.isEmpty(message)) {\n      message = \"Empty/NULL log message\";\n    }\n\n    for (LogAdapter adapter : logAdapters) {\n      if (adapter.isLoggable(priority, tag)) {\n        adapter.log(priority, tag, message);\n      }\n    }\n  }\n\n  @Override\n  public void clearLogAdapters() {\n    logAdapters.clear();\n  }\n\n  @Override\n  public void addAdapter(LogAdapter adapter) {\n    logAdapters.add(adapter);\n  }\n\n  /**\n   * This method is synchronized in order to avoid messy of logs' order.\n   */\n  private synchronized void log(int priority, Throwable throwable, String msg, Object... args) {\n    String tag = getTag();\n    String message = createMessage(msg, args);\n    log(priority, tag, message, throwable);\n  }\n\n  /**\n   * @return the appropriate tag based on local or global\n   */\n  private String getTag() {\n    String tag = localTag.get();\n    if (tag != null) {\n      localTag.remove();\n      return tag;\n    }\n    return null;\n  }\n\n  private String createMessage(String message, Object... args) {\n    return args == null || args.length == 0 ? message : String.format(message, args);\n  }\n}"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/PrettyFormatStrategy.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\npublic class PrettyFormatStrategy implements FormatStrategy {\n\n  /**\n   * Android's max limit for a log entry is ~4076 bytes,\n   * so 4000 bytes is used as chunk size since default charset\n   * is UTF-8\n   */\n  private static final int CHUNK_SIZE = 4000;\n\n  /**\n   * The minimum stack trace index, starts at this class after two native calls.\n   */\n  private static final int MIN_STACK_OFFSET = 5;\n\n  /**\n   * Drawing toolbox\n   */\n  private static final char TOP_LEFT_CORNER = '┌';\n  private static final char BOTTOM_LEFT_CORNER = '└';\n  private static final char MIDDLE_CORNER = '├';\n  private static final char HORIZONTAL_LINE = '│';\n  private static final String DOUBLE_DIVIDER = \"────────────────────────────────────────────────────────\";\n  private static final String SINGLE_DIVIDER = \"┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄\";\n  private static final String TOP_BORDER = TOP_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER;\n  private static final String BOTTOM_BORDER = BOTTOM_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER;\n  private static final String MIDDLE_BORDER = MIDDLE_CORNER + SINGLE_DIVIDER + SINGLE_DIVIDER;\n\n  private final int methodCount;\n  private final int methodOffset;\n  private final boolean showThreadInfo;\n  private final LogStrategy logStrategy;\n  private final String tag;\n\n  private PrettyFormatStrategy(Builder builder) {\n    methodCount = builder.methodCount;\n    methodOffset = builder.methodOffset;\n    showThreadInfo = builder.showThreadInfo;\n    logStrategy = builder.logStrategy;\n    tag = builder.tag;\n  }\n\n  public static Builder newBuilder() {\n    return new Builder();\n  }\n\n  @Override\n  public void log(int priority, String onceOnlyTag, String message) {\n    String tag = formatTag(onceOnlyTag);\n\n    logTopBorder(priority, tag);\n    logHeaderContent(priority, tag, methodCount);\n\n    //get bytes of message with system's default charset (which is UTF-8 for Android)\n    byte[] bytes = message.getBytes();\n    int length = bytes.length;\n    if (length <= CHUNK_SIZE) {\n      if (methodCount > 0) {\n        logDivider(priority, tag);\n      }\n      logContent(priority, tag, message);\n      logBottomBorder(priority, tag);\n      return;\n    }\n    if (methodCount > 0) {\n      logDivider(priority, tag);\n    }\n    for (int i = 0; i < length; i += CHUNK_SIZE) {\n      int count = Math.min(length - i, CHUNK_SIZE);\n      //create a new String with system's default charset (which is UTF-8 for Android)\n      logContent(priority, tag, new String(bytes, i, count));\n    }\n    logBottomBorder(priority, tag);\n  }\n\n  private void logTopBorder(int logType, String tag) {\n    logChunk(logType, tag, TOP_BORDER);\n  }\n\n  @SuppressWarnings(\"StringBufferReplaceableByString\")\n  private void logHeaderContent(int logType, String tag, int methodCount) {\n    StackTraceElement[] trace = Thread.currentThread().getStackTrace();\n    if (showThreadInfo) {\n      logChunk(logType, tag, HORIZONTAL_LINE + \" Thread: \" + Thread.currentThread().getName());\n      logDivider(logType, tag);\n    }\n    String level = \"\";\n\n    int stackOffset = getStackOffset(trace) + methodOffset;\n\n    //corresponding method count with the current stack may exceeds the stack trace. Trims the count\n    if (methodCount + stackOffset > trace.length) {\n      methodCount = trace.length - stackOffset - 1;\n    }\n\n    for (int i = methodCount; i > 0; i--) {\n      int stackIndex = i + stackOffset;\n      if (stackIndex >= trace.length) {\n        continue;\n      }\n      StringBuilder builder = new StringBuilder();\n      builder.append(HORIZONTAL_LINE)\n          .append(' ')\n          .append(level)\n          .append(getSimpleClassName(trace[stackIndex].getClassName()))\n          .append(\".\")\n          .append(trace[stackIndex].getMethodName())\n          .append(\" \")\n          .append(\" (\")\n          .append(trace[stackIndex].getFileName())\n          .append(\":\")\n          .append(trace[stackIndex].getLineNumber())\n          .append(\")\");\n      level += \"   \";\n      logChunk(logType, tag, builder.toString());\n    }\n  }\n\n  private void logBottomBorder(int logType, String tag) {\n    logChunk(logType, tag, BOTTOM_BORDER);\n  }\n\n  private void logDivider(int logType, String tag) {\n    logChunk(logType, tag, MIDDLE_BORDER);\n  }\n\n  private void logContent(int logType, String tag, String chunk) {\n    String[] lines = chunk.split(System.getProperty(\"line.separator\"));\n    for (String line : lines) {\n      logChunk(logType, tag, HORIZONTAL_LINE + \" \" + line);\n    }\n  }\n\n  private void logChunk(int priority, String tag, String chunk) {\n    logStrategy.log(priority, tag, chunk);\n  }\n\n  private String getSimpleClassName(String name) {\n    int lastIndex = name.lastIndexOf(\".\");\n    return name.substring(lastIndex + 1);\n  }\n\n  /**\n   * Determines the starting index of the stack trace, after method calls made by this class.\n   *\n   * @param trace the stack trace\n   * @return the stack offset\n   */\n  private int getStackOffset(StackTraceElement[] trace) {\n    for (int i = MIN_STACK_OFFSET; i < trace.length; i++) {\n      StackTraceElement e = trace[i];\n      String name = e.getClassName();\n      if (!name.equals(LoggerPrinter.class.getName()) && !name.equals(Logger.class.getName())) {\n        return --i;\n      }\n    }\n    return -1;\n  }\n\n  private String formatTag(String tag) {\n    if (!Utils.isEmpty(tag) && !Utils.equals(this.tag, tag)) {\n      return this.tag + \"-\" + tag;\n    }\n    return this.tag;\n  }\n\n  public static class Builder {\n    int methodCount = 2;\n    int methodOffset = 0;\n    boolean showThreadInfo = true;\n    LogStrategy logStrategy;\n    String tag = \"PRETTY_LOGGER\";\n\n    private Builder() {\n    }\n\n    public Builder methodCount(int val) {\n      methodCount = val;\n      return this;\n    }\n\n    public Builder methodOffset(int val) {\n      methodOffset = val;\n      return this;\n    }\n\n    public Builder showThreadInfo(boolean val) {\n      showThreadInfo = val;\n      return this;\n    }\n\n    public Builder logStrategy(LogStrategy val) {\n      logStrategy = val;\n      return this;\n    }\n\n    public Builder tag(String tag) {\n      this.tag = tag;\n      return this;\n    }\n\n    public PrettyFormatStrategy build() {\n      if (logStrategy == null) {\n        logStrategy = new LogcatLogStrategy();\n      }\n      return new PrettyFormatStrategy(this);\n    }\n  }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/Printer.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\npublic interface Printer {\n\n  void addAdapter(LogAdapter adapter);\n\n  Printer t(String tag);\n\n  void d(String message, Object... args);\n\n  void d(Object object);\n\n  void e(String message, Object... args);\n\n  void e(Throwable throwable, String message, Object... args);\n\n  void w(String message, Object... args);\n\n  void i(String message, Object... args);\n\n  void v(String message, Object... args);\n\n  void wtf(String message, Object... args);\n\n  /**\n   * Formats the given json content and print it\n   */\n  void json(String json);\n\n  /**\n   * Formats the given xml content and print it\n   */\n  void xml(String xml);\n\n  void log(int priority, String tag, String message, Throwable throwable);\n\n  void clearLogAdapters();\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/logger/Utils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.logger;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.net.UnknownHostException;\nimport java.util.Arrays;\n\n/**\n * Provides convenient methods to some common operations\n */\nfinal class Utils {\n\n  private Utils() {\n    // Hidden constructor.\n  }\n\n  /**\n   * Returns true if the string is null or 0-length.\n   *\n   * @param str the string to be examined\n   * @return true if str is null or zero length\n   */\n  static boolean isEmpty(CharSequence str) {\n    return str == null || str.length() == 0;\n  }\n\n  /**\n   * Returns true if a and b are equal, including if they are both null.\n   * <p><i>Note: In platform versions 1.1 and earlier, this method only worked well if\n   * both the arguments were instances of String.</i></p>\n   *\n   * @param a first CharSequence to check\n   * @param b second CharSequence to check\n   * @return true if a and b are equal\n   * <p>\n   * NOTE: Logic slightly change due to strict policy on CI -\n   * \"Inner assignments should be avoided\"\n   */\n  static boolean equals(CharSequence a, CharSequence b) {\n    if (a == b) return true;\n    if (a != null && b != null) {\n      int length = a.length();\n      if (length == b.length()) {\n        if (a instanceof String && b instanceof String) {\n          return a.equals(b);\n        } else {\n          for (int i = 0; i < length; i++) {\n            if (a.charAt(i) != b.charAt(i)) return false;\n          }\n          return true;\n        }\n      }\n    }\n    return false;\n  }\n\n  /**\n   * Copied from \"android.util.Log.getStackTraceString()\" in order to avoid usage of Android stack\n   * in unit tests.\n   *\n   * @return Stack trace in form of String\n   */\n  static String getStackTraceString(Throwable tr) {\n    if (tr == null) {\n      return \"\";\n    }\n\n    // This is to reduce the amount of log spew that apps do in the non-error\n    // condition of the network being unavailable.\n    Throwable t = tr;\n    while (t != null) {\n      if (t instanceof UnknownHostException) {\n        return \"\";\n      }\n      t = t.getCause();\n    }\n\n    StringWriter sw = new StringWriter();\n    PrintWriter pw = new PrintWriter(sw);\n    tr.printStackTrace(pw);\n    pw.flush();\n    return sw.toString();\n  }\n\n  static String logLevel(int value) {\n    switch (value) {\n      case Logger.VERBOSE:\n        return \"VERBOSE\";\n      case Logger.DEBUG:\n        return \"DEBUG\";\n      case Logger.INFO:\n        return \"INFO\";\n      case Logger.WARN:\n        return \"WARN\";\n      case Logger.ERROR:\n        return \"ERROR\";\n      case Logger.ASSERT:\n        return \"ASSERT\";\n      default:\n        return \"UNKNOWN\";\n    }\n  }\n\n  public static String toString(Object object) {\n    if (object == null) {\n      return \"null\";\n    }\n    if (!object.getClass().isArray()) {\n      return object.toString();\n    }\n    if (object instanceof boolean[]) {\n      return Arrays.toString((boolean[]) object);\n    }\n    if (object instanceof byte[]) {\n      return Arrays.toString((byte[]) object);\n    }\n    if (object instanceof char[]) {\n      return Arrays.toString((char[]) object);\n    }\n    if (object instanceof short[]) {\n      return Arrays.toString((short[]) object);\n    }\n    if (object instanceof int[]) {\n      return Arrays.toString((int[]) object);\n    }\n    if (object instanceof long[]) {\n      return Arrays.toString((long[]) object);\n    }\n    if (object instanceof float[]) {\n      return Arrays.toString((float[]) object);\n    }\n    if (object instanceof double[]) {\n      return Arrays.toString((double[]) object);\n    }\n    if (object instanceof Object[]) {\n      return Arrays.deepToString((Object[]) object);\n    }\n    return \"Couldn't find a correct type for the object\";\n  }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/walle/WalleChannelReader.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.walle;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.frame.walle.payload_reader.ChannelInfo;\nimport com.bzai.gamesdk.common.utils_base.frame.walle.payload_reader.ChannelReader;\n\nimport java.io.File;\nimport java.util.Map;\n\n/**\n * 集成美团的打多渠道标识方案，相关内容详看博客及文章，\n * 目前在SDK中是读取,写入是通过命令行写入\n *\n * https://tech.meituan.com/android-apk-v2-signature-scheme.html\n * https://github.com/Meituan-Dianping/walle\n */\npublic final class WalleChannelReader {\n    private WalleChannelReader() {\n        super();\n    }\n\n    /**\n     * get channel\n     *\n     * @param context context\n     * @return channel, null if not fount\n     */\n    public static String getChannel(final Context context) {\n        return getChannel(context, null);\n    }\n\n    /**\n     * get channel or default\n     *\n     * @param context context\n     * @param defaultChannel default channel\n     * @return channel, default if not fount\n     */\n    public static String getChannel(final Context context, final String defaultChannel) {\n        final ChannelInfo channelInfo = getChannelInfo(context);\n        if (channelInfo == null) {\n            return defaultChannel;\n        }\n        return channelInfo.getChannel();\n    }\n\n    /**\n     * get channel info (include channle & extraInfo)\n     *\n     * @param context context\n     * @return channel info\n     */\n    public static ChannelInfo getChannelInfo(final Context context) {\n        final String apkPath = getApkPath(context);\n        if (TextUtils.isEmpty(apkPath)) {\n            return null;\n        }\n        return ChannelReader.get(new File(apkPath));\n    }\n\n    /**\n     * get value by key\n     *\n     * @param context context\n     * @param key     the key you store\n     * @return value\n     */\n    public static String get(final Context context, final String key) {\n        final Map<String, String> channelMap = getChannelInfoMap(context);\n        if (channelMap == null) {\n            return null;\n        }\n        return channelMap.get(key);\n    }\n\n    /**\n     * get all channl info with map\n     *\n     * @param context context\n     * @return map\n     */\n    public static Map<String, String> getChannelInfoMap(final Context context) {\n        final String apkPath = getApkPath(context);\n        if (TextUtils.isEmpty(apkPath)) {\n            return null;\n        }\n        return ChannelReader.getMap(new File(apkPath));\n    }\n\n    private static String getApkPath(final Context context) {\n        String apkPath = null;\n        try {\n            final ApplicationInfo applicationInfo = context.getApplicationInfo();\n            if (applicationInfo == null) {\n                return null;\n            }\n            apkPath = applicationInfo.sourceDir;\n        } catch (Throwable e) {\n        }\n        return apkPath;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/walle/payload_reader/ApkUtil.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.walle.payload_reader;\n\nimport java.io.IOException;\nimport java.nio.BufferUnderflowException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nfinal class ApkUtil {\n    private ApkUtil() {\n        super();\n    }\n\n    /**\n     * APK Signing Block Magic Code: magic “APK Sig Block 42” (16 bytes)\n     * \"APK Sig Block 42\" : 41 50 4B 20 53 69 67 20 42 6C 6F 63 6B 20 34 32\n     */\n    public static final long APK_SIG_BLOCK_MAGIC_HI = 0x3234206b636f6c42L; // LITTLE_ENDIAN, High\n    public static final long APK_SIG_BLOCK_MAGIC_LO = 0x20676953204b5041L; // LITTLE_ENDIAN, Low\n    private static final int APK_SIG_BLOCK_MIN_SIZE = 32;\n\n    /*\n     The v2 signature of the APK is stored as an ID-value pair with ID 0x7109871a\n     (https://source.android.com/security/apksigning/v2.html#apk-signing-block)\n      */\n    public static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;\n\n    // Our Channel Block ID\n    public static final int APK_CHANNEL_BLOCK_ID = 0x71777777;\n\n    public static final String DEFAULT_CHARSET = \"UTF-8\";\n\n    private static final int ZIP_EOCD_REC_MIN_SIZE = 22;\n    private static final int ZIP_EOCD_REC_SIG = 0x06054b50;\n    private static final int UINT16_MAX_VALUE = 0xffff;\n    private static final int ZIP_EOCD_COMMENT_LENGTH_FIELD_OFFSET = 20;\n\n    public static long getCommentLength(final FileChannel fileChannel) throws IOException {\n        // End of central directory record (EOCD)\n        // Offset    Bytes     Description[23]\n        // 0           4       End of central directory signature = 0x06054b50\n        // 4           2       Number of this disk\n        // 6           2       Disk where central directory starts\n        // 8           2       Number of central directory records on this disk\n        // 10          2       Total number of central directory records\n        // 12          4       Size of central directory (bytes)\n        // 16          4       Offset of start of central directory, relative to start of archive\n        // 20          2       Comment length (n)\n        // 22          n       Comment\n        // For a zip with no archive comment, the\n        // end-of-central-directory record will be 22 bytes long, so\n        // we expect to find the EOCD marker 22 bytes from the end.\n\n\n        final long archiveSize = fileChannel.size();\n        if (archiveSize < ZIP_EOCD_REC_MIN_SIZE) {\n            throw new IOException(\"APK too small for ZIP End of Central Directory (EOCD) record\");\n        }\n        // ZIP End of Central Directory (EOCD) record is located at the very end of the ZIP archive.\n        // The record can be identified by its 4-byte signature/magic which is located at the very\n        // beginning of the record. A complication is that the record is variable-length because of\n        // the comment field.\n        // The algorithm for locating the ZIP EOCD record is as follows. We search backwards from\n        // end of the buffer for the EOCD record signature. Whenever we find a signature, we check\n        // the candidate record's comment length is such that the remainder of the record takes up\n        // exactly the remaining bytes in the buffer. The search is bounded because the maximum\n        // size of the comment field is 65535 bytes because the field is an unsigned 16-bit number.\n        final long maxCommentLength = Math.min(archiveSize - ZIP_EOCD_REC_MIN_SIZE, UINT16_MAX_VALUE);\n        final long eocdWithEmptyCommentStartPosition = archiveSize - ZIP_EOCD_REC_MIN_SIZE;\n        for (int expectedCommentLength = 0; expectedCommentLength <= maxCommentLength;\n             expectedCommentLength++) {\n            final long eocdStartPos = eocdWithEmptyCommentStartPosition - expectedCommentLength;\n\n            final ByteBuffer byteBuffer = ByteBuffer.allocate(4);\n            fileChannel.position(eocdStartPos);\n            fileChannel.read(byteBuffer);\n            byteBuffer.order(ByteOrder.LITTLE_ENDIAN);\n\n            if (byteBuffer.getInt(0) == ZIP_EOCD_REC_SIG) {\n                final ByteBuffer commentLengthByteBuffer = ByteBuffer.allocate(2);\n                fileChannel.position(eocdStartPos + ZIP_EOCD_COMMENT_LENGTH_FIELD_OFFSET);\n                fileChannel.read(commentLengthByteBuffer);\n                commentLengthByteBuffer.order(ByteOrder.LITTLE_ENDIAN);\n\n                final int actualCommentLength = commentLengthByteBuffer.getShort(0);\n                if (actualCommentLength == expectedCommentLength) {\n                    return actualCommentLength;\n                }\n            }\n        }\n        throw new IOException(\"ZIP End of Central Directory (EOCD) record not found\");\n    }\n\n    public static long findCentralDirStartOffset(final FileChannel fileChannel) throws IOException {\n        return findCentralDirStartOffset(fileChannel, getCommentLength(fileChannel));\n    }\n\n    public static long findCentralDirStartOffset(final FileChannel fileChannel, final long commentLength) throws IOException {\n        // End of central directory record (EOCD)\n        // Offset    Bytes     Description[23]\n        // 0           4       End of central directory signature = 0x06054b50\n        // 4           2       Number of this disk\n        // 6           2       Disk where central directory starts\n        // 8           2       Number of central directory records on this disk\n        // 10          2       Total number of central directory records\n        // 12          4       Size of central directory (bytes)\n        // 16          4       Offset of start of central directory, relative to start of archive\n        // 20          2       Comment length (n)\n        // 22          n       Comment\n        // For a zip with no archive comment, the\n        // end-of-central-directory record will be 22 bytes long, so\n        // we expect to find the EOCD marker 22 bytes from the end.\n\n        final ByteBuffer zipCentralDirectoryStart = ByteBuffer.allocate(4);\n        zipCentralDirectoryStart.order(ByteOrder.LITTLE_ENDIAN);\n        fileChannel.position(fileChannel.size() - commentLength - 6); // 6 = 2 (Comment length) + 4 (Offset of start of central directory, relative to start of archive)\n        fileChannel.read(zipCentralDirectoryStart);\n        final long centralDirStartOffset = zipCentralDirectoryStart.getInt(0);\n        return centralDirStartOffset;\n    }\n\n    public static Pair<ByteBuffer, Long> findApkSigningBlock(\n            final FileChannel fileChannel) throws IOException, SignatureNotFoundException {\n        final long centralDirOffset = findCentralDirStartOffset(fileChannel);\n        return findApkSigningBlock(fileChannel, centralDirOffset);\n    }\n\n    public static Pair<ByteBuffer, Long> findApkSigningBlock(\n            final FileChannel fileChannel, final long centralDirOffset) throws IOException, SignatureNotFoundException {\n\n        // Find the APK Signing Block. The block immediately precedes the Central Directory.\n\n        // FORMAT:\n        // OFFSET       DATA TYPE  DESCRIPTION\n        // * @+0  bytes uint64:    size in bytes (excluding this field)\n        // * @+8  bytes payload\n        // * @-24 bytes uint64:    size in bytes (same as the one above)\n        // * @-16 bytes uint128:   magic\n\n        if (centralDirOffset < APK_SIG_BLOCK_MIN_SIZE) {\n            throw new SignatureNotFoundException(\n                    \"APK too small for APK Signing Block. ZIP Central Directory offset: \"\n                            + centralDirOffset);\n        }\n        // Read the magic and offset in file from the footer section of the block:\n        // * uint64:   size of block\n        // * 16 bytes: magic\n        fileChannel.position(centralDirOffset - 24);\n        final ByteBuffer footer = ByteBuffer.allocate(24);\n        fileChannel.read(footer);\n        footer.order(ByteOrder.LITTLE_ENDIAN);\n        if ((footer.getLong(8) != APK_SIG_BLOCK_MAGIC_LO)\n                || (footer.getLong(16) != APK_SIG_BLOCK_MAGIC_HI)) {\n            throw new SignatureNotFoundException(\n                    \"No APK Signing Block before ZIP Central Directory\");\n        }\n        // Read and compare size fields\n        final long apkSigBlockSizeInFooter = footer.getLong(0);\n        if ((apkSigBlockSizeInFooter < footer.capacity())\n                || (apkSigBlockSizeInFooter > Integer.MAX_VALUE - 8)) {\n            throw new SignatureNotFoundException(\n                    \"APK Signing Block size out of range: \" + apkSigBlockSizeInFooter);\n        }\n        final int totalSize = (int) (apkSigBlockSizeInFooter + 8);\n        final long apkSigBlockOffset = centralDirOffset - totalSize;\n        if (apkSigBlockOffset < 0) {\n            throw new SignatureNotFoundException(\n                    \"APK Signing Block offset out of range: \" + apkSigBlockOffset);\n        }\n        fileChannel.position(apkSigBlockOffset);\n        final ByteBuffer apkSigBlock = ByteBuffer.allocate(totalSize);\n        fileChannel.read(apkSigBlock);\n        apkSigBlock.order(ByteOrder.LITTLE_ENDIAN);\n        final long apkSigBlockSizeInHeader = apkSigBlock.getLong(0);\n        if (apkSigBlockSizeInHeader != apkSigBlockSizeInFooter) {\n            throw new SignatureNotFoundException(\n                    \"APK Signing Block sizes in header and footer do not match: \"\n                            + apkSigBlockSizeInHeader + \" vs \" + apkSigBlockSizeInFooter);\n        }\n        return Pair.of(apkSigBlock, apkSigBlockOffset);\n    }\n\n    public static Map<Integer, ByteBuffer> findIdValues(final ByteBuffer apkSigningBlock) throws SignatureNotFoundException {\n        checkByteOrderLittleEndian(apkSigningBlock);\n        // FORMAT:\n        // OFFSET       DATA TYPE  DESCRIPTION\n        // * @+0  bytes uint64:    size in bytes (excluding this field)\n        // * @+8  bytes pairs\n        // * @-24 bytes uint64:    size in bytes (same as the one above)\n        // * @-16 bytes uint128:   magic\n        final ByteBuffer pairs = sliceFromTo(apkSigningBlock, 8, apkSigningBlock.capacity() - 24);\n\n        final Map<Integer, ByteBuffer> idValues = new LinkedHashMap<Integer, ByteBuffer>(); // keep order\n\n        int entryCount = 0;\n        while (pairs.hasRemaining()) {\n            entryCount++;\n            if (pairs.remaining() < 8) {\n                throw new SignatureNotFoundException(\n                        \"Insufficient data to read size of APK Signing Block entry #\" + entryCount);\n            }\n            final long lenLong = pairs.getLong();\n            if ((lenLong < 4) || (lenLong > Integer.MAX_VALUE)) {\n                throw new SignatureNotFoundException(\n                        \"APK Signing Block entry #\" + entryCount\n                                + \" size out of range: \" + lenLong);\n            }\n            final int len = (int) lenLong;\n            final int nextEntryPos = pairs.position() + len;\n            if (len > pairs.remaining()) {\n                throw new SignatureNotFoundException(\n                        \"APK Signing Block entry #\" + entryCount + \" size out of range: \" + len\n                                + \", available: \" + pairs.remaining());\n            }\n            final int id = pairs.getInt();\n            idValues.put(id, getByteBuffer(pairs, len - 4));\n\n            pairs.position(nextEntryPos);\n        }\n\n        return idValues;\n    }\n\n    /**\n     * Returns new byte buffer whose content is a shared subsequence of this buffer's content\n     * between the specified start (inclusive) and end (exclusive) positions. As opposed to\n     * {@link ByteBuffer#slice()}, the returned buffer's byte order is the same as the source\n     * buffer's byte order.\n     */\n    private static ByteBuffer sliceFromTo(final ByteBuffer source, final int start, final int end) {\n        if (start < 0) {\n            throw new IllegalArgumentException(\"start: \" + start);\n        }\n        if (end < start) {\n            throw new IllegalArgumentException(\"end < start: \" + end + \" < \" + start);\n        }\n        final int capacity = source.capacity();\n        if (end > source.capacity()) {\n            throw new IllegalArgumentException(\"end > capacity: \" + end + \" > \" + capacity);\n        }\n        final int originalLimit = source.limit();\n        final int originalPosition = source.position();\n        try {\n            source.position(0);\n            source.limit(end);\n            source.position(start);\n            final ByteBuffer result = source.slice();\n            result.order(source.order());\n            return result;\n        } finally {\n            source.position(0);\n            source.limit(originalLimit);\n            source.position(originalPosition);\n        }\n    }\n\n    /**\n     * Relative <em>get</em> method for reading {@code size} number of bytes from the current\n     * position of this buffer.\n     * <p>\n     * <p>This method reads the next {@code size} bytes at this buffer's current position,\n     * returning them as a {@code ByteBuffer} with start set to 0, limit and capacity set to\n     * {@code size}, byte order set to this buffer's byte order; and then increments the position by\n     * {@code size}.\n     */\n    private static ByteBuffer getByteBuffer(final ByteBuffer source, final int size)\n            throws BufferUnderflowException {\n        if (size < 0) {\n            throw new IllegalArgumentException(\"size: \" + size);\n        }\n        final int originalLimit = source.limit();\n        final int position = source.position();\n        final int limit = position + size;\n        if ((limit < position) || (limit > originalLimit)) {\n            throw new BufferUnderflowException();\n        }\n        source.limit(limit);\n        try {\n            final ByteBuffer result = source.slice();\n            result.order(source.order());\n            source.position(limit);\n            return result;\n        } finally {\n            source.limit(originalLimit);\n        }\n    }\n\n    private static void checkByteOrderLittleEndian(final ByteBuffer buffer) {\n        if (buffer.order() != ByteOrder.LITTLE_ENDIAN) {\n            throw new IllegalArgumentException(\"ByteBuffer byte order must be little endian\");\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/walle/payload_reader/ChannelInfo.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.walle.payload_reader;\n\nimport java.util.Map;\n\n/**\n * Created by chentong on 17/11/2016.\n */\npublic class ChannelInfo {\n    private final String channel;\n    private final Map<String, String> extraInfo;\n\n    public ChannelInfo(final String channel, final Map<String, String> extraInfo) {\n        this.channel = channel;\n        this.extraInfo = extraInfo;\n    }\n\n    public String getChannel() {\n        return channel;\n    }\n\n    public Map<String, String> getExtraInfo() {\n        return extraInfo;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/walle/payload_reader/ChannelReader.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.walle.payload_reader;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\n\npublic final class ChannelReader {\n    public static final String CHANNEL_KEY = \"channel\";\n\n    private ChannelReader() {\n        super();\n    }\n\n    /**\n     * easy api for get channel & extra info.<br/>\n     *\n     * @param apkFile apk file\n     * @return null if not found\n     */\n    public static ChannelInfo get(final File apkFile) {\n        final Map<String, String> result = getMap(apkFile);\n        if (result == null) {\n            return null;\n        }\n        final String channel = result.get(CHANNEL_KEY);\n        result.remove(CHANNEL_KEY);\n        return new ChannelInfo(channel, result);\n    }\n\n    /**\n     * get channel & extra info by map, use {@link ChannelReader#CHANNEL_KEY PayloadReader.CHANNEL_KEY} get channel\n     *\n     * @param apkFile apk file\n     * @return null if not found\n     */\n    public static Map<String, String> getMap(final File apkFile) {\n        try {\n            final String rawString = getRaw(apkFile);\n            if (rawString == null) {\n                return null;\n            }\n            final JSONObject jsonObject = new JSONObject(rawString);\n            final Iterator keys = jsonObject.keys();\n            final Map<String, String> result = new HashMap<String, String>();\n            while (keys.hasNext()) {\n                final String key = keys.next().toString();\n                result.put(key, jsonObject.getString(key));\n            }\n            return result;\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    /**\n     * get raw string from channel id\n     *\n     * @param apkFile apk file\n     * @return null if not found\n     */\n    public static String getRaw(final File apkFile) {\n        return  PayloadReader.getString(apkFile, ApkUtil.APK_CHANNEL_BLOCK_ID);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/walle/payload_reader/Pair.java",
    "content": "/*\n * Copyright (C) 2016 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.bzai.gamesdk.common.utils_base.frame.walle.payload_reader;\n\n/**\n * Pair of two elements.\n */\nfinal class Pair<A, B> {\n    private final A mFirst;\n    private final B mSecond;\n\n    private Pair(final A first, final B second) {\n        mFirst = first;\n        mSecond = second;\n    }\n\n    public static <A, B> Pair<A, B> of(final A first, final B second) {\n        return new Pair<A, B>(first, second);\n    }\n\n    public A getFirst() {\n        return mFirst;\n    }\n\n    public B getSecond() {\n        return mSecond;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((mFirst == null) ? 0 : mFirst.hashCode());\n        result = prime * result + ((mSecond == null) ? 0 : mSecond.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(final Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        @SuppressWarnings(\"rawtypes\")\n        final Pair other = (Pair) obj;\n        if (mFirst == null) {\n            if (other.mFirst != null) {\n                return false;\n            }\n        } else if (!mFirst.equals(other.mFirst)) {\n            return false;\n        }\n        if (mSecond == null) {\n            if (other.mSecond != null) {\n                return false;\n            }\n        } else if (!mSecond.equals(other.mSecond)) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/walle/payload_reader/PayloadReader.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.walle.payload_reader;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.util.Arrays;\nimport java.util.Map;\n\npublic final class PayloadReader {\n    private PayloadReader() {\n        super();\n    }\n\n    /**\n     * get string (UTF-8) by id\n     *\n     * @param apkFile apk file\n     * @return null if not found\n     */\n    public static String getString(final File apkFile, final int id) {\n        final byte[] bytes = PayloadReader.get(apkFile, id);\n        if (bytes == null) {\n            return null;\n        }\n        try {\n            return new String(bytes, ApkUtil.DEFAULT_CHARSET);\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    /**\n     * get bytes by id <br/>\n     *\n     * @param apkFile apk file\n     * @param id      id\n     * @return bytes\n     */\n    public static byte[] get(final File apkFile, final int id) {\n        final Map<Integer, ByteBuffer> idValues = getAll(apkFile);\n        if (idValues == null) {\n            return null;\n        }\n        final ByteBuffer byteBuffer = idValues.get(id);\n        if (byteBuffer == null) {\n            return null;\n        }\n        return getBytes(byteBuffer);\n    }\n\n    /**\n     * get data from byteBuffer\n     *\n     * @param byteBuffer buffer\n     * @return useful data\n     */\n    private static byte[] getBytes(final ByteBuffer byteBuffer) {\n        final byte[] array = byteBuffer.array();\n        final int arrayOffset = byteBuffer.arrayOffset();\n        return Arrays.copyOfRange(array, arrayOffset + byteBuffer.position(),\n                arrayOffset + byteBuffer.limit());\n    }\n\n    /**\n     * get all custom (id, buffer) <br/>\n     * Note: get final from byteBuffer, please use {@link PayloadReader#getBytes getBytes}\n     *\n     * @param apkFile apk file\n     * @return all custom (id, buffer)\n     */\n    private static Map<Integer, ByteBuffer> getAll(final File apkFile) {\n        Map<Integer, ByteBuffer> idValues = null;\n        try {\n            RandomAccessFile randomAccessFile = null;\n            FileChannel fileChannel = null;\n            try {\n                randomAccessFile = new RandomAccessFile(apkFile, \"r\");\n                fileChannel = randomAccessFile.getChannel();\n                final ByteBuffer apkSigningBlock2 = ApkUtil.findApkSigningBlock(fileChannel).getFirst();\n                idValues = ApkUtil.findIdValues(apkSigningBlock2);\n            } catch (IOException ignore) {\n            } finally {\n                try {\n                    if (fileChannel != null) {\n                        fileChannel.close();\n                    }\n                } catch (IOException ignore) {\n                }\n                try {\n                    if (randomAccessFile != null) {\n                        randomAccessFile.close();\n                    }\n                } catch (IOException ignore) {\n                }\n            }\n        } catch (SignatureNotFoundException ignore) {\n        }\n\n        return idValues;\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/frame/walle/payload_reader/SignatureNotFoundException.java",
    "content": "package com.bzai.gamesdk.common.utils_base.frame.walle.payload_reader;\n\n\npublic class SignatureNotFoundException extends Exception {\n    private static final long serialVersionUID = 1L;\n\n    public SignatureNotFoundException(final String message) {\n        super(message);\n    }\n\n    public SignatureNotFoundException(final String message, final Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/interfaces/CallBackListener.java",
    "content": "package com.bzai.gamesdk.common.utils_base.interfaces;\n\n\n/**\n * Created by bzai on 2018/4/9.\n * 项目回调基类\n */\npublic interface CallBackListener<T>  {\n\n    /**\n     * 成功回调\n     * @param t 详细信息\n     */\n    void onSuccess(T t);\n\n    /**\n     * 失败回调\n     *\n     * @param code 错误码\n     * @param msg 错误详细描述信息\n     */\n    void onFailure(int code, String msg);\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/interfaces/LifeCycleInterface.java",
    "content": "package com.bzai.gamesdk.common.utils_base.interfaces;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\n\n\n/**\n * Created by bzai on 2018/04/09.\n * 生命周期接口\n */\n\npublic interface LifeCycleInterface {\n\n    void onCreate(Context context, Bundle savedInstanceState);\n\n    void onStart(Context context);\n\n    void onResume(Context context);\n\n    void onPause(Context context);\n\n    void onStop(Context context);\n\n    void onRestart(Context context);\n\n    void onDestroy(Context context);\n\n    void onNewIntent(Context context, Intent intent);\n\n    void onActivityResult(Context context, int requestCode, int resultCode, Intent data);\n\n    void onRequestPermissionsResult(Context context, int requestCode, String[] permissions, int[] grantResults);\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/net/RequestExecutor.java",
    "content": "package com.bzai.gamesdk.common.utils_base.net;\n\nimport com.bzai.gamesdk.common.utils_base.net.request.IRequestManager;\nimport com.bzai.gamesdk.common.utils_base.net.request.RequestCallback;\nimport com.bzai.gamesdk.common.utils_base.net.request.VolleyRequestManager;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Created by bzai on 2018/04/09.\n * 网络请求接口类\n *\n * 网络框架要替换成别的时候，实现具体封装就OK了,并修改具体实现\n * 比如换成okhttp写法 ：return new OkHttpRequestManager();\n *\n */\n\npublic class RequestExecutor {\n\n    public static final String GET = \"GET\";\n    public static final String POST = \"POST\";\n\n    private IRequestManager iRequestManager;\n\n    private String method;\n    private String url;\n    private String header;\n    private String userAgent;\n    private Map<String,Object> params;\n    private RequestCallback requestCallback;\n\n    private RequestExecutor(RequestExecutor.Builder builder){\n\n        this.method = builder.method;\n        this.url = builder.url;\n        this.header = builder.header;\n        this.userAgent = builder.userAgent;\n        this.params = builder.params;\n        this.requestCallback = builder.requestCallback;\n    }\n\n    public void startRequest(){\n\n        iRequestManager = new VolleyRequestManager();\n        iRequestManager.setHeader(header);\n        iRequestManager.setUserAgent(userAgent);\n\n        if (RequestExecutor.GET.equals(method)){\n\n            iRequestManager.get(url,params,requestCallback);\n\n        }else if (RequestExecutor.POST.equals(method)){\n\n            iRequestManager.post(url,params,requestCallback);\n        }\n\n    }\n\n    /**\n     * 取消当前的网络请求，\n     */\n    public void cancel(){\n        iRequestManager.cancel();\n    }\n\n    public static class Builder{\n\n        private String method;\n        private String url;\n        private String header;\n        private String userAgent;\n        private Map<String,Object> params;\n        private RequestCallback requestCallback;\n\n        public RequestExecutor build(){\n            return new RequestExecutor(this);\n        }\n\n        public RequestExecutor.Builder setMethod(String method){\n            this.method = method;\n            return this;\n        }\n\n        public RequestExecutor.Builder setUrl(String url){\n            this.url = url;\n            return this;\n        }\n\n        public RequestExecutor.Builder setHeader(String header){\n            this.header = header;\n            return this;\n        }\n\n        public RequestExecutor.Builder setUserAgent(String userAgent){\n            this.userAgent = userAgent;\n            return this;\n        }\n\n        public RequestExecutor.Builder setParams(HashMap<String,Object> params){\n            this.params = params;\n            return this;\n        }\n\n        public RequestExecutor.Builder setRequestCallback(RequestCallback requestCallback){\n            this.requestCallback = requestCallback;\n            return this;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/net/base/VolleyRequestWrapper.java",
    "content": "package com.bzai.gamesdk.common.utils_base.net.base;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox.StringRequest;\n\n\n/**\n * Created by bzai on 2018/04/09.\n *\n * 封装Volley StringRequest为网络请求基础基类\n *\n */\npublic abstract class VolleyRequestWrapper extends StringRequest {\n\n    private VolleySingleton baseVolleySingleton;\n\n    private VolleyRequestWrapper(int method, String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {\n        super(method, url, listener, errorListener);\n    }\n\n    public VolleyRequestWrapper(Context context, int method, String url, final VolleyResponseListener listener){\n\n        this(method, url, new Response.Listener<String>() {\n\n            @Override\n            public void onResponse(String response) {\n                    if(listener != null){\n                        listener.onResponseSuccess(response);\n                    }\n            }\n\n        }, new Response.ErrorListener() {\n\n            @Override\n            public void onErrorResponse(VolleyError error) {\n                if(listener != null){\n                    listener.onResponseFailure(error);\n                }\n            }\n        });\n\n        baseVolleySingleton = VolleySingleton.getInstance(context.getApplicationContext());\n    }\n\n    /**\n     * 添加请求到队列\n     */\n    protected void sendRequest() {\n        addRequestToQueue(this);\n    }\n\n    private <T> void addRequestToQueue(Request<T> request) {\n        if (request == null)\n            return;\n        baseVolleySingleton.addToRequestQueue(request);\n    }\n\n    /**\n     * 取消当前的网络请求\n     */\n    @Override\n    public void cancel() {\n        super.cancel();\n    }\n\n    /**\n     * 取消特定的网络请求\n     * @param tag\n     */\n    protected void cancelByTag(String tag){\n        if (TextUtils.isEmpty(tag)){\n            return;\n        }\n        baseVolleySingleton.getRequestQueue().cancelAll(tag);\n    }\n}\n\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/net/base/VolleyResponseListener.java",
    "content": "package com.bzai.gamesdk.common.utils_base.net.base;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyError;\n\n\n/**\n * Created by bzai on 2018/04/09.\n *\n * 网络请求回调，封装Volley请求回调\n */\npublic interface VolleyResponseListener{\n\n    /**\n     * 网络请求成功\n     * @param response\n     */\n    void onResponseSuccess(String response);\n\n    /**\n     * 网络请求失败\n     *\n     * @param error\n     */\n    void onResponseFailure(VolleyError error);\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/net/base/VolleySingleton.java",
    "content": "package com.bzai.gamesdk.common.utils_base.net.base;\n\nimport android.content.Context;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.DefaultRetryPolicy;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.RequestQueue;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox.Volley;\n\n/**\n * Created by bzai on 2018/04/09.\n *\n * 封装Volley实例对象为单例\n */\npublic class VolleySingleton {\n\n\tprivate static volatile VolleySingleton mInstance;\n\tprivate Context mContext;\n\tprivate RequestQueue mRequestQueue;\n\n\tprivate VolleySingleton(Context context) {\n\t\tthis.mContext = context;\n\t\tthis.mRequestQueue = getRequestQueue();\n\t}\n\n\tpublic static VolleySingleton getInstance(Context context) {\n\t\tif (mInstance == null) {\n\t\t\tsynchronized (VolleySingleton.class) {\n\t\t\t\tif (mInstance == null)\n\t\t\t\t\tmInstance = new VolleySingleton(context);\n\t\t\t}\n\t\t}\n\t\treturn mInstance;\n\t}\n\n\t/**\n\t * 获取 volley RequestQueue 实例\n\t */\n\tpublic RequestQueue getRequestQueue() {\n\t\tif (mRequestQueue == null) {\n\t\t\tmRequestQueue = Volley.newRequestQueue(mContext);\n\t\t}\n\t\treturn mRequestQueue;\n\t}\n\n\t/**\n\t * 将Request加入RequestQueue\n\t */\n\tpublic <T> void addToRequestQueue(Request<T> request) {\n\t\tif (request == null)\n\t\t\treturn;\n\t\trequest.setShouldCache(false); //不设置缓存\n\t\trequest.setRetryPolicy(new DefaultRetryPolicy(15 * 1000,0,\n\t\t\t\tDefaultRetryPolicy.DEFAULT_BACKOFF_MULT));\n\t\tgetRequestQueue().add(request);\n\t}\n\n\t/**\n\t * 将特定的Request从RequestQueue清除\n\t * @param key\n\t */\n\tpublic void removeRequest(String key) {\n\t\tgetRequestQueue().getCache().remove(key);\n\t}\n\n\t/**\n\t * 停止网络请求(所有的)\n\t */\n\tpublic void destroy(){\n\t\tgetRequestQueue().stop();\n\t\tmInstance = null;\n\t}\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/net/impl/BaseRequest.java",
    "content": "package com.bzai.gamesdk.common.utils_base.net.impl;\n\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.cache.ApplicationCache;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.AuthFailureError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NetworkResponse;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Request;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.Response;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.toolbox.HttpHeaderParser;\nimport com.bzai.gamesdk.common.utils_base.net.base.VolleyRequestWrapper;\nimport com.bzai.gamesdk.common.utils_base.net.base.VolleyResponseListener;\nimport com.bzai.gamesdk.common.utils_base.utils.CodeUtils;\nimport com.bzai.gamesdk.common.utils_base.utils.JsonUtils;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLDecoder;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.zip.GZIPInputStream;\n\n/**\n * Created by bzai on 2018/04/09.\n *\n * Volley网络请求基类，所有的网络请求都继承这个类\n */\npublic class BaseRequest extends VolleyRequestWrapper {\n\n    private static final String TAG = \"BaseRequest\";\n\n    private int method;\n    private String url;\n    private Map<String, Object> mParamMap = new HashMap<>();\n\n    private String authorization;\n    private String userAgent;\n    private Map<String, String> headers;\n\n    private BaseRequest(int method, String url, VolleyResponseListener listener) {\n        super(ApplicationCache.getInstance().getApplicationContext(), method, url, listener);\n    }\n\n\n    /*GET 和 POST 需要额外处理下url 和 bodyMap**/\n    public BaseRequest(int method, String url, Map<String, Object> bodyMap, VolleyResponseListener listener) {\n        this(method, method == Method.GET ? buildParamsUrl(url, bodyMap) : url,listener);\n        this.method = method;\n        this.url = url;\n        this.mParamMap = bodyMap == null ? mParamMap : bodyMap;\n    }\n\n\n    /**\n     * 拼接Get请求链接\n     * @param url\n     * @param args Get请求的参数\n     * @return\n     */\n    private static String buildParamsUrl(String url, Map<String,Object> args){\n\n        url += \"?\";\n        if (args == null) {\n            args = new HashMap<>();\n        }\n        return  CodeUtils.appendParams(new StringBuilder(url),args);\n    }\n\n    /**\n     * 封装请求头\n     * @return\n     */\n    @Override\n    public Map<String, String> getHeaders() {\n\n        String header = getAuthorization(method == Request.Method.GET ? \"GET\" : \"POST\", url, mParamMap);\n        String userAgentValue = getUserAgent();\n        headers = new HashMap<>();\n        headers.put(\"Authorization\", header);\n        headers.put(\"User-Agent\", userAgentValue);\n        // 默认启动gzip压缩\n        headers.put(\"Accept-Encoding\", \"gzip\");\n        return headers;\n    }\n\n    /**\n     * 对外提供接口来设置 authorization\n     * @param authorization\n     */\n    public void setAuthorization(String authorization) {\n        this.authorization = authorization;\n    }\n\n    public String getAuthorization(String method, String url, Map<String, ?> requestParams) {\n        if (!TextUtils.isEmpty(authorization)) {\n            return authorization;\n        }\n\n        return BaseRequestUtils.getOAuthHeader(method,url,requestParams);\n    }\n\n    /**\n     * 对外提供接口来设置 userAgent\n     * @param userAgent\n     */\n    public void setUserAgent(String userAgent) {\n        this.userAgent = userAgent;\n    }\n\n    private String getUserAgent() {\n        if (!TextUtils.isEmpty(userAgent)) {\n            return userAgent;\n        }\n        return BaseRequestUtils.getUserAgent();\n    }\n\n    /**\n     * 封装请求body内容\n     * @return\n     * @throws AuthFailureError\n     */\n    @Override\n    public byte[] getBody() throws AuthFailureError {\n        byte[] content = null;\n        String mStrBody = CodeUtils.appendParams(new StringBuilder(),mParamMap);\n        try {\n            content = mStrBody.getBytes();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        return content;\n    }\n\n    /**\n     * 根据网络返回数据，进行解压解密等操作\n     */\n    @Override\n    protected Response<String> parseNetworkResponse(NetworkResponse response) {\n\n        if (response == null || response.data == null) {\n            return Response.error(new VolleyError());\n        }\n\n        byte[] data;// volley缓存是针对处理后的response对象，故只针对response的data进行处理\n        if (response.headers.containsKey(\"Content-Encoding\") && response.headers.get(\"Content-Encoding\").equals(\"gzip\")) {\n            data = decompressZipToByte(response.data);\n            if (data == null) {\n                return Response.error(new VolleyError());\n            }\n        } else {\n            data = response.data;\n        }\n        Response<String> rsp = parseResponse(response, data);\n        if (rsp != null) {\n            return rsp;\n        } else {\n            return Response.error(new VolleyError());\n        }\n    }\n\n\n    /**\n     * 解压byte数组为对应的字符串\n     *\n     * @param body\n     * @return\n     */\n    public static byte[] decompressZipToByte(byte[] body) {\n\n        if (body == null || body.length == 0) {\n            return null;\n        }\n        try {\n            ByteArrayOutputStream out = new ByteArrayOutputStream();\n            ByteArrayInputStream in = new ByteArrayInputStream(body);\n            // 判断是否是GZIP格式\n            int ss = (body[0] & 0xff) | ((body[1] & 0xff) << 8);\n            if (ss == GZIPInputStream.GZIP_MAGIC) {\n                GZIPInputStream gunzip = new GZIPInputStream(in);\n                byte[] buffer = new byte[256];\n                int n;\n                while ((n = gunzip.read(buffer)) >= 0) {\n                    out.write(buffer, 0, n);\n                }\n                return out.toByteArray();\n            } else {\n                // 非gzip压缩，直接返回结果\n                return body;\n            }\n        } catch (Exception e) {\n\n        }\n        return null;\n    }\n\n    /**\n     * 解析请求成功返回数据\n     *\n     * @param response\n     * @param data\n     * @return\n     */\n    protected Response<String> parseResponse(NetworkResponse response, byte[] data) {\n        String parsed = null;\n        try {\n            parsed = new String(data, \"UTF-8\");\n            printNetInfo(true, response, parsed);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return Response.success(parsed,\n                HttpHeaderParser.parseCacheHeaders(response));\n    }\n\n\n    /**\n     * 解析请求失败返回数据\n     *\n     * @param volleyError the error retrieved from the network\n     * @return\n     */\n    @Override\n    protected VolleyError parseNetworkError(VolleyError volleyError) {\n        if (volleyError.networkResponse != null) {\n            printNetInfo(false, volleyError.networkResponse, new String(volleyError.networkResponse.data));\n        } else {\n            printNetInfo(false, null, volleyError.toString());\n        }\n        return super.parseNetworkError(volleyError);\n    }\n\n    /**\n     * 输出网络请求详情日志\n     *\n     * @param response\n     * @param parsed\n     */\n    private void printNetInfo(boolean success, NetworkResponse response, String parsed) {\n        try {\n            StringBuffer sb = new StringBuffer();\n            sb.append(\"network request info\");\n            sb.append(\"\\nmethod:\" + (this.getMethod() == Method.GET ? \"get\" : \"post\"));\n            sb.append(\"\\nurl:\" + URLDecoder.decode(this.getUrl(), \"UTF-8\"));\n            sb.append(\"\\nheaders:\" + this.headers);\n            sb.append(\"\\nAuthorization:\" + this.headers.get(\"Authorization\"));\n            sb.append(\"\\nbody:\" + URLDecoder.decode(new String(this.getBody()), \"UTF-8\"));\n            sb.append(\"\\nstatusCode:\" + (response != null ? response.statusCode : \"-1\"));\n            sb.append(\"\\nnetworkTimeMs:\" + (response != null ? response.networkTimeMs : \"15000\"));\n            if (!TextUtils.isEmpty(parsed))\n                sb.append(\"\\nresponse:\\n\" + CodeUtils.Unicode2GBK(JsonUtils.isJson(parsed) ? JsonUtils.format(parsed) : parsed));\n\n            if (!success)\n                LogUtils.debug_i(TAG, sb.toString());\n            else\n                LogUtils.debug_i(TAG, sb.toString());\n\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n    }\n\n\n    /**\n     * 发送网络请求\n     */\n    @Override\n    public void sendRequest() {\n        super.sendRequest();\n        try {\n            LogUtils.debug_i(TAG, \"url:\" + URLDecoder.decode(this.getUrl(), \"UTF-8\"));\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 取消网络请求\n     */\n    @Override\n    public void cancel() {\n        super.cancel();\n        try {\n            LogUtils.debug_i(TAG, \"cancel url:\" + URLDecoder.decode(this.getUrl(), \"UTF-8\"));\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/net/impl/BaseRequestCallback.java",
    "content": "package com.bzai.gamesdk.common.utils_base.net.impl;\n\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.config.ErrCode;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.AuthFailureError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NetworkError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.NoConnectionError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.ParseError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.RedirectError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.ServerError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.TimeoutError;\nimport com.bzai.gamesdk.common.utils_base.frame.google.volley.VolleyError;\nimport com.bzai.gamesdk.common.utils_base.net.base.VolleyResponseListener;\n\n/**\n * Created by bzai on 2018/04/09.\n *\n * 处理请求返回数据分类，通过泛型将结果数据转换成对应实体回传\n * \n * \n */\npublic abstract class BaseRequestCallback<T> implements VolleyResponseListener{\n\n    @Override\n    public void onResponseSuccess(String response) {\n\n        if (TextUtils.isEmpty(response)){\n            onFailure(ErrCode.NET_DATA_NULL, \"net data null\");//网络请求成功,但是数据为空错误。\n            return;\n        }\n\n        onSuccess((T) response);\n\n    }\n\n    @Override\n    public void onResponseFailure(VolleyError error) {\n        //处理下回调信息\n//        onFailure(ErrCode.NET_ERROR, error.toString());\n        Class errorClass = error.getClass();\n        if (errorClass.equals(AuthFailureError.class)){//网络认证失败\n            onFailure(ErrCode.NET_ERROR, \"Network AuthFailureError\");\n\n        }else if (errorClass.equals(NetworkError.class)){ //网络错误\n            onFailure(ErrCode.NET_ERROR, \"NetworkError\");\n\n        }else if (errorClass.equals(NoConnectionError.class)){ //无网络连接\n            onFailure(ErrCode.NET_ERROR, \"Network NoConnectionError\");\n\n        }else if (errorClass.equals(ParseError.class)){ //服务器响应无法解析\n            onFailure(ErrCode.NET_ERROR, \"Network ParseError\");\n\n        }else if (errorClass.equals(RedirectError.class)){ //已存在重定向\n            onFailure(ErrCode.NET_ERROR, \"Network RedirectError\");\n\n        }else if (errorClass.equals(ServerError.class)){ //服务器错误响应\n            onFailure(ErrCode.NET_ERROR, \"Network ServerError\");\n\n        }else if (errorClass.equals(TimeoutError.class)){ //连接超时\n            onFailure(ErrCode.NET_ERROR, \"Network TimeoutError\");\n        }\n    }\n\n\n    /**\n     * 成功后回调方法\n     *\n     * @param t\n     */\n    public abstract void onSuccess(T t);\n\n    /**\n     * 失败后回调方法\n     *\n     * @param errCode\n     * @param msg\n     */\n    public abstract void onFailure(int errCode, String msg);\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/net/impl/BaseRequestUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.net.impl;\n\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.bzai.gamesdk.common.utils_base.cache.ApplicationCache;\nimport com.bzai.gamesdk.common.utils_base.utils.ContextUtils;\nimport com.bzai.gamesdk.common.utils_base.utils.Md5Utils;\n\nimport java.net.URLEncoder;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Random;\n\n/**\n * Created by bzai on 2018/4/16.\n * <p>\n * Desc:\n *\n * 用于获取 OAuthHeader 和 userAgent\n *\n * 目前只是简单处理\n *\n * TODO 后续可用于做网络请求的加解密处理,\n *\n */\n\npublic class BaseRequestUtils {\n\n    public static final String SIGNATURE_METHOD = \"MD5\";\n    public static final String VERSION_1_0 = \"1.0\";\n\n    public static String getUserAgent(){\n\n        Context context = ApplicationCache.getInstance().getApplicationContext().getApplicationContext();\n        StringBuilder sb = new StringBuilder(256);\n        sb.append(\"SYSDK/1.0\")\n                .append(\"(android:\").append(Build.VERSION.RELEASE)\n                .append(\";app_version:\").append(ContextUtils.getVersionName(context))\n                .append(\";package:\").append(context.getPackageName())\n                .append(\";network_type:\").append(ContextUtils.getNetworkType(context))\n                .append(\";imei:\").append(ContextUtils.getDeviceId(context))\n                .append(\";device_brand:\").append(Build.BRAND)\n                .append(\";device_model:\").append(Build.MODEL)\n                .append(\";resolution:\").append(ContextUtils.getResolutionAsString(context))\n                .append(\";cpu_freq:\").append(ContextUtils.getCpuFre())\n                .append(\";game_name:\").append(URLEncoder.encode(ContextUtils.getLabel(context)))\n                .append(\";sim_type:\").append(ContextUtils.getSimCardType(context))\n                .append(\";platform:\").append(ContextUtils.getDeviceName())\n                .append(\")\");\n\n        return sb.toString();\n\n    }\n\n\n    public static String getOAuthHeader(String method, String url, Map<String, ?> requestParams){\n\n        String OAuthMethod = SIGNATURE_METHOD;\n        String version = VERSION_1_0;\n        String timeStamp = generateTimestamp();\n        String nonce = generateNonce();\n\n\n        HashMap<String,Object> map = new HashMap<>();\n        map.put(\"method\",method);\n        map.put(\"url\",url);\n        map.put(\"requestParams\",requestParams.toString());\n\n        String md5 = Md5Utils.getMd5(map.toString());\n\n\n        StringBuilder sb = new StringBuilder(256);\n        sb.append(\"SYSDK/1.0\")\n                .append(\"(OAuthMethod:\").append(OAuthMethod)\n                .append(\";version:\").append(version)\n                .append(\";time:\").append(timeStamp)\n                .append(\";nonce:\").append(nonce)\n                .append(\";md5:\").append(md5)\n                .append(\")\");\n\n        String header = sb.toString();\n\n        return header;\n    }\n\n\n    public static String generateTimestamp() {\n        return Long.toString(System.currentTimeMillis() / 1000L);\n    }\n\n    public static String generateNonce() {\n        return Long.toString(new Random().nextLong());\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/net/impl/bean/ResponseResult.java",
    "content": "package com.bzai.gamesdk.common.utils_base.net.impl.bean;\n\n\nimport com.bzai.gamesdk.common.utils_base.proguard.ProguardObject;\n\n/**\n * Created by bzai.xiao on 2017/12/20.\n *\n * 服务端数据格式实体\n */\npublic class ResponseResult<T> extends ProguardObject {\n\n    private String ret;\n    private String msg;\n    private T data;\n\n    public String getCode() {\n        return ret;\n    }\n\n    public void setCode(String ret) {\n        this.ret = ret;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    public void setMsg(String msg) {\n        this.msg = msg;\n    }\n\n    public T getResult() {\n        return data;\n    }\n\n    public void setResult(T data) {\n        this.data = data;\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/net/request/IRequestManager.java",
    "content": "package com.bzai.gamesdk.common.utils_base.net.request;\n\nimport java.util.Map;\n\n/**\n * Created by bzai on 2018/04/09.\n *\n * 将网络请求方法抽象抽离出来\n */\n\npublic interface IRequestManager {\n\n    void get(String url, Map<String, Object> params, RequestCallback requestCallback);\n\n    void post(String url, Map<String, Object> params, RequestCallback requestCallback);\n\n    void cancel();\n\n    void setHeader(String header);\n\n    void setUserAgent(String UserAgent);\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/net/request/RequestCallback.java",
    "content": "package com.bzai.gamesdk.common.utils_base.net.request;\n\n\n/**\n * Created by bzai on 2018/04/09.\n */\n\npublic interface RequestCallback {\n\n    /**\n     * 网络请求回调成功\n     * @param object\n     */\n    void onSuccess(Object object);\n\n\n    /**\n     * 网络请求回调失败\n     * @param errCode\n     * @param message\n     */\n    void onFailure(int errCode, String message);\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/net/request/VolleyRequestManager.java",
    "content": "package com.bzai.gamesdk.common.utils_base.net.request;\n\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.net.base.VolleyResponseListener;\nimport com.bzai.gamesdk.common.utils_base.net.impl.BaseRequest;\nimport com.bzai.gamesdk.common.utils_base.net.impl.BaseRequestCallback;\n\nimport java.util.Map;\n\n/**\n * Created by bzai on 2018/04/09.\n */\n\npublic class VolleyRequestManager implements IRequestManager {\n\n    private BaseRequest request;\n    private String header;\n    private String userAgent;\n\n    /**\n     * 设置请求头 header\n     * @param header\n     */\n    @Override\n    public void setHeader(String header){\n        this.header = header;\n    }\n\n    /**\n     * 设置 userAgent\n     * @param userAgent\n     */\n    @Override\n    public void setUserAgent(String userAgent){\n        this.userAgent = userAgent;\n    }\n\n\n    /**\n     * 注意：BaseRequestCallback 回调的泛型为String\n     * @param url\n     * @param params\n     * @param requestCallback\n     */\n    @Override\n    public void get(String url, Map<String,Object> params, final RequestCallback requestCallback) {\n\n        this.request = GetRequest.create(url, params, new BaseRequestCallback<String>() {\n\n            @Override\n            public void onSuccess(String result) {\n                requestCallback.onSuccess(result);\n            }\n\n            @Override\n            public void onFailure(int errCodeType, String msg) {\n                requestCallback.onFailure(errCodeType,msg);\n            }\n\n        });\n\n        if (!TextUtils.isEmpty(header)){\n            this.request.setAuthorization(header);\n        }\n\n        if (!TextUtils.isEmpty(userAgent)){\n            this.request.setUserAgent(userAgent);\n        }\n\n        this.request.sendRequest();\n\n    }\n\n    /**\n     * 注意：BaseRequestCallback 回调的泛型为String\n     * @param url\n     * @param params\n     * @param requestCallback\n     */\n    @Override\n    public void post(String url, Map<String,Object> params, final RequestCallback requestCallback) {\n\n        this.request = PostRequest.create(url, params, new BaseRequestCallback<String>() {\n\n            @Override\n            public void onSuccess(String result) {\n                requestCallback.onSuccess(result);\n            }\n\n            @Override\n            public void onFailure(int errCodeType, String msg) {\n                requestCallback.onFailure(errCodeType,msg);\n            }\n\n        });\n\n        if (!TextUtils.isEmpty(header)){\n            this.request.setAuthorization(header);\n        }\n\n        if (!TextUtils.isEmpty(userAgent)){\n            this.request.setUserAgent(userAgent);\n        }\n\n        this.request.sendRequest();\n\n    }\n\n    /**\n     * 取消网络请求\n     */\n    @Override\n    public void cancel() {\n        this.request.cancel();\n    }\n\n\n    /************************************************* 网络请求 ************************************************/\n\n    private static class GetRequest extends BaseRequest {\n\n        public GetRequest(int method, String url, Map<String, Object> bodyMap, VolleyResponseListener listener) {\n            super(method, url, bodyMap, listener);\n        }\n\n        public static GetRequest create(String url, Map<String, Object> bodyMap, BaseRequestCallback listener){\n            return new GetRequest(Method.GET,url,bodyMap,listener);\n        }\n\n    }\n\n    private static class PostRequest extends BaseRequest {\n\n        public PostRequest(int method, String url, Map<String, Object> bodyMap, VolleyResponseListener listener) {\n            super(method, url, bodyMap, listener);\n        }\n\n        public static PostRequest create(String url, Map<String, Object> bodyMap, BaseRequestCallback listener){\n            return new PostRequest(Method.POST,url,bodyMap,listener);\n        }\n\n    }\n\n    /************************************************* 网络请求 ************************************************/\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/parse/channel/Channel.java",
    "content": "package com.bzai.gamesdk.common.utils_base.parse.channel;\n\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.res.Configuration;\nimport android.os.Bundle;\n\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.interfaces.LifeCycleInterface;\nimport com.bzai.gamesdk.common.utils_base.proguard.ProguardInterface;\n\nimport java.util.HashMap;\n\n/**\n * Created by bzai on 2018/4/11.\n * <p>\n * Desc:\n *\n *  用于描述渠道SDK的顶层接口\n *\n */\n\npublic abstract class Channel extends ChannelListenerImpl implements LifeCycleInterface, ProguardInterface {\n\n\n    /*****************************   Channel 加载必须接口    **********************************/\n\n\n    /**\n     * 实例渠道插件对象，必须实现\n     */\n    protected abstract void initChannel();\n\n    public ChannelBeanList.ChannelBean channelBean;\n\n    @Override\n    public String toString() {\n        return \"Channel{\" + \"channelBean=\" + channelBean +'}';\n    }\n\n\n    /****************************** 必须业务逻辑接口 ****************************/\n\n\n    public static final String PARAMS_OAUTH_TYPE = \"PARAMS_OAUTH_TYPE\";\n    public static final String PARAMS_OAUTH_URL = \"PARAMS_OAUTH_URL\";\n\n\n    /**\n     * 返回渠道的ID(用于识别渠道)\n     */\n    public abstract String getChannelID();\n\n\n    /**\n     * 由于个别渠道只简单实现登录、支付接口，\n     * 对外提供该接口给CP判断该接口是否已实现\n     * @param FuncType\n     * @return\n     */\n    public abstract boolean isSupport(int FuncType);\n\n    /**\n     * 渠道SDK初始化\n     */\n    public abstract void init(Context context, HashMap<String,Object> initMap, CallBackListener initCallBackListener);\n\n    /**\n     * 渠道SDK登录\n     */\n    public abstract void login(Context context, HashMap<String,Object> loginMap, CallBackListener loginCallBackListener);\n\n    /**\n     * 渠道切换账号\n     */\n    public abstract void switchAccount(Context context, CallBackListener changeAccountCallBackLister);\n\n    /**\n     * 渠道SDK注销账号\n     */\n    public abstract void logout(Context context, CallBackListener logoutCallBackLister);\n\n    /**\n     * 渠道SDK支付\n     */\n    public abstract void pay(Context context, HashMap<String,Object> payMap, CallBackListener payCallBackListener);\n\n    /**\n     * 渠道SDK退出\n     */\n    public abstract void exit(Context context, CallBackListener exitCallBackLister);\n\n\n    /****************************** 非必须业务逻辑接口 ****************************/\n\n\n    /**\n     * 返回渠道版本号\n     */\n    public String getChannelVersion(){\n        return null;\n    }\n\n    /**\n     * 渠道SDK个人中心\n     */\n    public void enterPlatform(Context context, CallBackListener enterPlatformCallBackLister){}\n\n    /**\n     * 显示渠道SDK悬浮窗\n     */\n    public void showFloatView(Context context){}\n\n    /**\n     * 关闭渠道SDK悬浮窗\n     */\n    public void dismissFloatView(Context context){}\n\n    /**\n     * 渠道SDK上报数据\n     */\n    public void reportData(Context context, HashMap<String,Object> dataMap){}\n\n    /**\n     * 横竖屏\n     * @return true为横屏，false为竖屏\n     */\n    public boolean getOrientation(Context context){\n        boolean isLandscape = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;\n        return isLandscape;\n    }\n\n\n\n\n    /****************************** 非业务逻辑 生命周期接口 ****************************/\n\n    @Override\n    public void onCreate(Context context, Bundle savedInstanceState) {}\n\n    @Override\n    public void onStart(Context context) {}\n\n    @Override\n    public void onResume(Context context) {}\n\n    @Override\n    public void onPause(Context context) {}\n\n    @Override\n    public void onStop(Context context) {}\n\n    @Override\n    public void onRestart(Context context) {}\n\n    @Override\n    public void onDestroy(Context context) {}\n\n    @Override\n    public void onNewIntent(Context context, Intent intent) {}\n\n    @Override\n    public void onActivityResult(Context context, int requestCode, int resultCode, Intent data) {}\n\n    @Override\n    public void onRequestPermissionsResult(Context context, int requestCode, String[] permissions, int[] grantResults) {}\n\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/parse/channel/ChannelBeanList.java",
    "content": "package com.bzai.gamesdk.common.utils_base.parse.channel;\n\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.proguard.ProguardObject;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport java.lang.reflect.Method;\nimport java.util.List;\n\n/**\n * Created by bzai on 2018/4/11.\n * <p>\n * Desc:\n *\n *   渠道SDK实体类\n *\n *   只提供get方法，不提供set\n *\n */\n\npublic class ChannelBeanList extends ProguardObject{\n\n    private List<ChannelBean> channel; //注意解析的名字要跟文件一致，不然会导致解析错误\n\n    public List<ChannelBean> getChannel(){\n        return channel;\n    }\n\n    public static class ChannelBean extends ProguardObject {\n\n        private static final String TAG = \"ChannelBean\";\n        /**\n         * 反射插件的单例模式方法\n         * 返回的插件可能为空\n         *\n         * @return\n         */\n        public Channel invokeGetInstance() {\n            Channel channel = null;\n            Class<?> glass = null;\n            if (TextUtils.isEmpty(class_name)) {\n                LogUtils.debug_w(TAG, \"invokeGetInstance: the class_name is blank\");\n                return channel;\n            }\n            try {\n                glass = Class.forName(class_name);\n            } catch (ClassNotFoundException e) {\n                LogUtils.debug_w(TAG, \"invokeGetInstance: \" + \"do not find \" + class_name);\n            }\n            try {\n                //尝试调用getInstance\n                Method m = glass\n                        .getDeclaredMethod(\"getInstance\", new Class<?>[]{});\n                m.setAccessible(true);\n                channel = (Channel) m.invoke(null, new Object[]{});\n            } catch (NoSuchMethodException e1) {\n                //调用getInstance失败后，尝试new其对象\n                try {\n                    channel = (Channel) glass.newInstance();\n                } catch (Exception exception) {\n                    LogUtils.debug_w(TAG, \"glass.newInstance(): \" + \"do not find \" + class_name);\n                }\n            } catch (Exception exception) {\n                LogUtils.debug_w(TAG, \"glass.getInstance(): \" + \"do not find \" + class_name);\n            }\n\n            if (channel == null) {\n                LogUtils.debug_w(TAG, class_name + \" is not empty.\");\n            }else {\n                channel.channelBean = this;\n            }\n\n            return channel;\n        }\n\n        /**\n         * project_name : 渠道SDK名称\n         * class_name : 渠道SDK入口类\n         * description : 项目描述\n         * version : 版本信息\n         */\n\n        private String channel_name;\n        private String class_name;\n        private String description;\n        private String version;\n\n        public String getChannel_name() {\n            return channel_name;\n        }\n\n        public String getClass_name() {\n            return class_name;\n        }\n\n        public String getDescription() {\n            return description;\n        }\n\n        public String getVersion() {\n            return version;\n        }\n\n        @Override\n        public String toString() {\n            return \"ChannelBean{\" +\n                    \" channel_name='\" + channel_name + '\\'' +\n                    \", class_name='\" + class_name + '\\'' +\n                    \", description='\" + description + '\\'' +\n                    \", version='\" + version + '\\'' +\n                    '}';\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/parse/channel/ChannelListenerImpl.java",
    "content": "package com.bzai.gamesdk.common.utils_base.parse.channel;\n\n\nimport com.bzai.gamesdk.common.utils_base.config.ErrCode;\nimport com.bzai.gamesdk.common.utils_base.config.TypeConfig;\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\n\nimport java.util.HashMap;\n\n/**\n * Created by bzai on 2018/4/13.\n * <p>\n * Desc:\n *\n *  统一封装渠道回调信息,Channel 需继承\n */\n\npublic class ChannelListenerImpl {\n\n    private HashMap<String,Object> loginAuthData;\n\n    /**\n     * 初始化成功\n     */\n    public void initOnSuccess(CallBackListener callBackListener){\n        if (callBackListener != null){\n            callBackListener.onSuccess(null);\n        }\n    }\n\n\n    /**\n     * 登录成功\n     */\n    public void loginOnSuccess(String oathUrl, CallBackListener callBackListener){\n\n        if (loginAuthData == null){\n            loginAuthData = new HashMap<>();\n        }\n\n        loginAuthData.put(Channel.PARAMS_OAUTH_URL,oathUrl); //授权的参数信息\n        loginAuthData.put(Channel.PARAMS_OAUTH_TYPE, TypeConfig.LOGIN); //授权的事件类型\n\n        if (callBackListener != null){\n            callBackListener.onSuccess(loginAuthData);\n        }\n    }\n\n\n    /**\n     * 登录失败\n     */\n    public void loginOnFail(String errorMessage, CallBackListener callBackListener){\n\n        if (callBackListener != null){\n            callBackListener.onFailure(ErrCode.CHANNEL_LOGIN_FAIL,errorMessage);\n        }\n\n    }\n\n    /**\n     * 登录取消\n     */\n    public void loginOnCancel(String errorMessage, CallBackListener callBackListener){\n\n        if (callBackListener != null){\n            callBackListener.onFailure(ErrCode.CHANNEL_LOGIN_CANCEL,errorMessage);\n        }\n\n    }\n\n\n    /**\n     * 切换账号成功\n     */\n    public void switchAccountOnSuccess(String oathUrl, CallBackListener callBackListener){\n\n        if (loginAuthData == null){\n            loginAuthData = new HashMap<>();\n        }\n\n        loginAuthData.put(Channel.PARAMS_OAUTH_URL,oathUrl); //授权的参数信息\n        loginAuthData.put(Channel.PARAMS_OAUTH_TYPE, TypeConfig.SWITCHACCOUNT); //授权的事件类型\n\n        if (callBackListener != null){\n            callBackListener.onSuccess(loginAuthData);\n        }\n    }\n\n    /**\n     * 切换账号成功\n     */\n    public void switchAccountOnFail(String errorMessage, CallBackListener callBackListener){\n\n        if (callBackListener != null){\n            callBackListener.onFailure(ErrCode.CHANNEL_SWITCH_ACCOUNT_FAIL,errorMessage);\n        }\n\n    }\n\n\n    /**\n     * 切换账号成功\n     */\n    public void switchAccountOnCancel(String errorMessage, CallBackListener callBackListener){\n\n        if (callBackListener != null){\n            callBackListener.onFailure(ErrCode.CHANNEL_SWITCH_ACCOUNT_CANCEL,errorMessage);\n        }\n\n    }\n\n    /**\n     * 注销成功\n     */\n    public void logoutOnSuccess(CallBackListener callBackListener){\n\n        if (loginAuthData == null){\n            loginAuthData = new HashMap<>();\n        }\n\n        loginAuthData.put(Channel.PARAMS_OAUTH_URL,\"\"); //授权的参数信息\n        loginAuthData.put(Channel.PARAMS_OAUTH_TYPE, TypeConfig.LOGOUT); //授权的事件类型\n\n        if (callBackListener != null){\n            callBackListener.onSuccess(loginAuthData);\n        }\n    }\n\n    /**\n     * 注销失败\n     */\n    public void logoutOnFail(String errorMessage, CallBackListener callBackListener){\n\n        if (callBackListener != null){\n            callBackListener.onFailure(ErrCode.CHANNEL_LOGOUT_FAIL,errorMessage);\n        }\n    }\n\n    /**\n     * 注销取消\n     */\n    public void logoutOnCancel(String errorMessage, CallBackListener callBackListener){\n\n        if (callBackListener != null){\n            callBackListener.onFailure(ErrCode.CHANNEL_LOGOUT_CANCEL,errorMessage);\n        }\n    }\n\n\n    /**\n     * 支付成功\n     * @param callBackListener\n     */\n    public void payOnSuccess(CallBackListener callBackListener){\n\n        if (callBackListener != null){\n            callBackListener.onSuccess(null);\n        }\n    }\n\n    /**\n     * 当渠道不能正确返回支付结果时，返回该字段\n     * @param callBackListener\n     */\n    public void payOnComplete(CallBackListener callBackListener){\n\n        if (callBackListener != null){\n            callBackListener.onFailure(ErrCode.NO_PAY_RESULT,\"pay complete\");\n        }\n    }\n\n    /**\n     * 统一渠道不存在退出框\n     */\n    public void channelNotExitDialog(CallBackListener callBackListener){\n\n        if (callBackListener != null){\n            callBackListener.onFailure(ErrCode.NO_EXIT_DIALOG,\"channel not exitDialog\");\n        }\n\n    }\n\n\n    /**\n     * 统一失败回调\n     */\n    public void OnFailure(String errorMessage, CallBackListener callBackListener){\n\n        if (callBackListener != null){\n            callBackListener.onFailure(ErrCode.FAILURE,errorMessage);\n        }\n\n    }\n\n    /**\n     * 统一取消回调\n     */\n    public void  OnCancel(CallBackListener callBackListener){\n\n        if (callBackListener != null){\n            callBackListener.onFailure(ErrCode.CANCEL,\"cancel\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/parse/channel/ChannelManager.java",
    "content": "package com.bzai.gamesdk.common.utils_base.parse.channel;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.utils.FileUtils;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport java.util.HashMap;\nimport java.util.Set;\n\n\n/**\n * Created by bzai on 2018/4/11.\n * <p>\n * Desc:\n *\n *  渠道管理类\n *\n */\n\npublic class ChannelManager {\n\n    private static final String TAG = \"ChannelManager\";\n    private static String CHANNEL_CONFIG = \"Channel_config.txt\";\n\n    private Channel channel;\n    private HashMap<String, ChannelBeanList.ChannelBean> channelBeans = new HashMap<>();\n\n    /********************* 同步锁双重检测机制实现单例模式（懒加载）********************/\n    private volatile static ChannelManager channelManager;\n    public static ChannelManager init(Context context) {\n        if (channelManager == null) {\n            synchronized (ChannelManager.class) {\n                if (channelManager == null) {\n                    channelManager = new ChannelManager(context);\n                }\n            }\n        }\n        return channelManager;\n    }\n\n    public static ChannelManager getInstance() {\n        return channelManager;\n    }\n    /********************* 同步锁双重检测机制实现单例模式 ********************/\n\n    private ChannelManager(Context context) {\n        parse(context, CHANNEL_CONFIG);\n    }\n\n    private void parse(Context context, String pluginFilePath) {\n        //从配置文件中，读取插件配置\n        StringBuilder channelContent = FileUtils.readAssetsFile(context, pluginFilePath);\n        String strChannelContent = String.valueOf(channelContent);\n\n        //进行解析\n        Gson gson = new Gson();\n        if (!TextUtils.isEmpty(strChannelContent)) {\n            try {\n\n                ChannelBeanList channelBeanList = gson.fromJson(strChannelContent, ChannelBeanList.class);\n\n                if (channelBeanList.getChannel() != null && channelBeanList.getChannel().size() != 0) {\n\n                    //如果解析结果无误，载入到listPluginBean中去\n                    for (ChannelBeanList.ChannelBean channelBean : channelBeanList.getChannel()) {\n                        channelBeans.put(channelBean.getChannel_name(), channelBean);\n                    }\n                    //打印解析结果\n                    LogUtils.debug_i(TAG, CHANNEL_CONFIG +\" parse: \\n\" + channelBeans.toString());\n                } else {\n                    //解析结果出错\n                    LogUtils.e(TAG, CHANNEL_CONFIG + \" parse error.\");\n                }\n\n            } catch (Exception e) {\n                //解析结果出错\n                LogUtils.e(TAG, CHANNEL_CONFIG + \" parse exception.\");\n                e.printStackTrace();\n            }\n        }else {\n            LogUtils.e(TAG, CHANNEL_CONFIG + \" parse is blank.\");\n        }\n\n    }\n\n\n    private boolean hasLoaded;\n    private static HashMap<String, Channel> ChannelLists = new HashMap<String, Channel>();\n\n\n    /**\n     * 加载所有的Channel,可能存在多个渠道\n     */\n    public synchronized void loadAllChannels() {\n        if (hasLoaded) {\n            return;\n        }\n        HashMap<String, ChannelBeanList.ChannelBean> entries = channelBeans;\n        Set<String> set = entries.keySet();\n        for (String key : set) {\n            loadChannel(key);\n        }\n        LogUtils.debug_i(TAG, \"loadAllPlugins:\" + ChannelLists.toString());\n        hasLoaded = true;\n    }\n\n\n    /**\n     * 加载一个渠道，返回的channel可能为空\n     *\n     * @param channelName\n     * @return\n     * @throws RuntimeException\n     */\n    private Channel loadChannel(String channelName) throws RuntimeException {\n\n        // 1.查看从配置文件中读取的插件列表，是否存在此插件\n        HashMap<String, ChannelBeanList.ChannelBean> entries = channelBeans;\n        ChannelBeanList.ChannelBean channelBean = entries.get(channelName);\n        if (channelBean == null) {\n            LogUtils.debug_i(TAG, \"The channel [\" +  channelName + \"] does not exists in \" + CHANNEL_CONFIG);\n            return null;\n        }\n        Channel channel = null;\n        // 2.调用其单例模式方法\n        channel = channelBean.invokeGetInstance();\n        if (channel != null) {\n            // 3.反射初始化插件\n            channel.initChannel();\n            // 4.将已加载好的插件，添加到插件列表中去\n            ChannelLists.put(channelName, channel);\n        }\n        return channel;\n    }\n\n\n    /**\n     * 获取特定渠道\n     * 可能为空\n     *\n     * @param channelName\n     * @return\n     */\n    public Channel getChannel(String channelName) {\n        if (!hasLoaded) {\n            LogUtils.debug_i(TAG, \"getChannel: \" + channelName + \"Channel not loaded yet\");\n            return null;\n        }\n        Channel channel = null;\n        HashMap<String, Channel> entries = ChannelLists;\n        channel = entries.get(channelName);\n        return channel;\n    }\n\n\n\n    /**\n     * 当前的加载渠道SDK(只有一个渠道配置时，且渠道名为channel)\n     */\n    public void loadChannel(){\n\n        ChannelBeanList.ChannelBean channelBean = channelBeans.get(\"channel\");\n        if (channelBean == null){\n            LogUtils.debug_d(TAG, \"The channel does not exists in \" + CHANNEL_CONFIG);\n            return;\n        }\n\n        Channel channel = null;\n        channel = channelBean.invokeGetInstance();\n        if (channel != null){\n            channel.initChannel();\n            this.channel = channel;\n        }\n    }\n\n    /**\n     * 返回当前渠道名为channel的渠道对象\n     * @return\n     */\n    public Channel getChannel(){\n        return channel;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/parse/plugin/Plugin.java",
    "content": "package com.bzai.gamesdk.common.utils_base.parse.plugin;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport com.bzai.gamesdk.common.utils_base.interfaces.LifeCycleInterface;\nimport com.bzai.gamesdk.common.utils_base.proguard.ProguardInterface;\n\n\n/**\n * Created by bzai on 2018/4/9.\n * 基础功能插件基类\n */\n\npublic class Plugin implements LifeCycleInterface, ProguardInterface {\n\n    private static final String TAG = \"Plugin\";\n\n    public PluginBeanList.PluginBean pluginBean;\n\n    private boolean hasInited;\n\n    protected synchronized void initPlugin() {\n        if (hasInited) {\n            return;\n        }\n        hasInited = true;\n    }\n\n    @Override\n    public String toString() {\n        return \"Plugin{\" + \"pluginMessage=\" + pluginBean + \", hasInited=\" + hasInited + '}';\n    }\n\n    /****************************************生命周期方法*********************************************/\n\n\n    public void onCreate(Context context, Bundle savedInstanceState) {\n    }\n\n    public void onStart(Context context) {\n    }\n\n    public void onResume(Context context) {\n    }\n\n    public void onPause(Context context) {\n    }\n\n    public void onStop(Context context) {\n    }\n\n    public void onRestart(Context context) {\n    }\n\n    public void onDestroy(Context context) {\n    }\n\n    public void onNewIntent(Context context, Intent intent){\n\n    }\n\n    public void onActivityResult(Context context, int requestCode, int resultCode, Intent data) {\n    }\n\n    public void onRequestPermissionsResult(Context context, int requestCode, String[] permissions, int[] grantResults) {\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/parse/plugin/PluginBeanList.java",
    "content": "package com.bzai.gamesdk.common.utils_base.parse.plugin;\n\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.proguard.ProguardObject;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport java.lang.reflect.Method;\nimport java.util.List;\n\n/**\n * Created by bzai on 2018/4/9.\n * 功能插件的实体基类\n *\n * 只提供get方法，不提供set\n */\n\npublic class PluginBeanList extends ProguardObject{\n\n    private List<PluginBean> plugin; //注意解析的名字要跟文件一致，不然会导致解析错误\n\n    public List<PluginBean> getPlugin() {\n        return plugin;\n    }\n\n    public static class PluginBean extends ProguardObject {\n\n        private static final String TAG = \"PluginBean\";\n\n        /**\n         * 反射插件的单例模式方法\n         * 返回的插件可能为空\n         *\n         * @return\n         */\n        public Plugin invokeGetInstance() {\n            Plugin plugin = null;\n            Class<?> glass = null;\n            if (TextUtils.isEmpty(class_name)){\n                LogUtils.debug_i(TAG, \"invokeGetInstance: the class_name is blank\");\n                return plugin;\n            }\n            try {\n                glass = Class.forName(class_name);\n            } catch (ClassNotFoundException e) {\n                LogUtils.debug_i(TAG, \"invokeGetInstance: \" + \"do not find \" + class_name );\n            }\n            try {\n                //尝试调用getInstance\n                Method m = glass.getDeclaredMethod(\"getInstance\", new Class<?>[]{});\n                m.setAccessible(true);\n                plugin = (Plugin) m.invoke(null, new Object[]{});\n            } catch (NoSuchMethodException e1) {\n                //调用getInstance失败后，尝试new其对象\n                try {\n                    plugin = (Plugin) glass.newInstance();\n                } catch (Exception exception) {\n                    LogUtils.debug_w(TAG, \"glass.newInstance(): \" + \"do not find \" + class_name);\n                }\n            } catch (Exception exception) {\n                LogUtils.debug_w(TAG, \"glass.getInstance(): \" + \"do not find \" + class_name);\n            }\n\n            if (plugin == null) {\n                LogUtils.debug_i(TAG, class_name + \" is empty.\");\n            } else {\n                plugin.pluginBean = this;\n            }\n            return plugin;\n        }\n\n        /**\n         * plugin_name : 插件名称\n         * class_name ：插件入口类\n         * description : 插件描述\n         * version : 插件版本\n         */\n\n        private String plugin_name;\n        private String class_name;\n        private String description;\n        private String version;\n\n        public String getPlugin_name() {\n            return plugin_name;\n        }\n\n        public String getClass_name() {\n            return class_name;\n        }\n\n        public String getDescription() {\n            return description;\n        }\n\n        public String getVersion() {\n            return version;\n        }\n\n        @Override\n        public String toString() {\n            return \"PluginBean{\" +\n                    \" plugin_name='\" + plugin_name + '\\'' +\n                    \", class_name='\" + class_name + '\\'' +\n                    \", description='\" + description + '\\'' +\n                    \", version='\" + version + '\\'' +\n                    '}';\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/parse/plugin/PluginManager.java",
    "content": "package com.bzai.gamesdk.common.utils_base.parse.plugin;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.utils.FileUtils;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport java.util.HashMap;\nimport java.util.Set;\n\n/**\n * Created by bzai on 2018/4/9.\n * 插件管理类\n */\n\npublic class PluginManager extends PluginReflectApi{\n\n    private static final String TAG = \"PluginManager\";\n    public static String PLUGIN_CONFIG = \"Plugin_config.txt\";\n\n\n    private static HashMap<String, PluginBeanList.PluginBean> PluginBeans = new HashMap<>();\n\n    /********************* 同步锁双重检测机制实现单例模式（懒加载）********************/\n    private volatile static PluginManager pluginManager;\n    public static PluginManager init(Context context) {\n        if (pluginManager == null) {\n            synchronized (PluginManager.class) {\n                if (pluginManager == null) {\n                    pluginManager = new PluginManager(context);\n                }\n            }\n        }\n        return pluginManager;\n    }\n\n    public static PluginManager getInstance(){\n        return pluginManager;\n    }\n    /********************* 同步锁双重检测机制实现单例模式（懒加载）********************/\n\n\n    private PluginManager(Context context) {\n        parse(context, PLUGIN_CONFIG);\n    }\n\n    /**\n     * 读取配置文件\n     * @param context\n     * @param pluginFilePath\n     */\n    private void parse(Context context, String pluginFilePath) {\n        //从配置文件中，读取插件配置\n        StringBuilder pluginContent = FileUtils.readAssetsFile(context, pluginFilePath);\n        String strPluginContent = String.valueOf(pluginContent);\n\n        //进行解析\n        Gson gson = new Gson();\n        if (!TextUtils.isEmpty(strPluginContent)) {\n            try {\n\n                PluginBeanList pluginBeanList = gson.fromJson(strPluginContent, PluginBeanList.class);\n                if (pluginBeanList.getPlugin() != null && pluginBeanList.getPlugin().size() != 0) {\n                    //如果解析结果无误，载入到listPluginBean中去\n                    for (PluginBeanList.PluginBean projectBean : pluginBeanList.getPlugin()) {\n                        PluginBeans.put(projectBean.getPlugin_name(), projectBean);\n                    }\n                    //打印解析结果\n                    LogUtils.debug_i(TAG, PLUGIN_CONFIG +\" parse: \\n\" + PluginBeans.toString());\n                } else {\n                    //解析结果出错\n                    LogUtils.e(TAG, PLUGIN_CONFIG + \" parse error.\");\n                }\n\n            } catch (Exception e) {\n                //解析结果出错\n                LogUtils.e(TAG, PLUGIN_CONFIG + \" parse exception.\");\n                e.printStackTrace();\n            }\n        }else {\n\n            LogUtils.e(TAG, PLUGIN_CONFIG + \" parse is blank\");\n        }\n    }\n\n    private boolean hasLoaded;\n    private static HashMap<String, Plugin> PluginLists = new HashMap<String, Plugin>();\n\n    /**\n     * 加载所有的插件\n     */\n    public synchronized void loadAllPlugins() {\n        if (hasLoaded) {\n            return;\n        }\n        HashMap<String, PluginBeanList.PluginBean> entries = PluginBeans;\n        Set<String> set = entries.keySet();\n        for (String key : set) {\n            loadPlugin(key);\n        }\n        LogUtils.debug_i(TAG, \"loadAllPlugins:\" + PluginLists.toString());\n        hasLoaded = true;\n    }\n\n    /**\n     * 加载一个插件，返回的插件可能为空\n     *\n     * @param pluginName\n     * @return\n     * @throws RuntimeException\n     */\n    private Plugin loadPlugin(String pluginName) throws RuntimeException {\n\n        // 1.查看从配置文件中读取的插件列表，是否存在此插件\n        HashMap<String, PluginBeanList.PluginBean> entries = PluginBeans;\n        PluginBeanList.PluginBean pluginBean = entries.get(pluginName);\n        if (pluginBean == null) {\n            LogUtils.debug_i(TAG, \"The plugin [\" +  pluginName + \"] does not exists in \" + PLUGIN_CONFIG);\n            return null;\n        }\n        Plugin Plugin = null;\n        // 2.调用其单例模式方法\n        Plugin = pluginBean.invokeGetInstance();\n        if (Plugin != null) {\n            // 3.反射初始化插件\n            Plugin.initPlugin();\n            // 4.将已加载好的插件，添加到插件列表中去\n            PluginLists.put(pluginName, Plugin);\n        }\n        return Plugin;\n    }\n\n    /**\n     * 获取特定插件\n     * 可能为空\n     *\n     * @param pluginName\n     * @return\n     */\n    public Plugin getPlugin(String pluginName) {\n        if (!hasLoaded) {\n            LogUtils.debug_i(TAG, \"getPlugin: \" + pluginName + \"Plugin not loaded yet\");\n            return null;\n        }\n        Plugin p = null;\n        HashMap<String, Plugin> entries = PluginLists;\n        p = entries.get(pluginName);\n        return p;\n    }\n\n    /******************************* 生命周期接口 *********************************/\n\n    public void onCreate(Context context, Bundle savedInstanceState) {\n        Set<String> set = PluginLists.keySet();\n        for (String key : set) {\n            Plugin plugin = PluginLists.get(key);\n            plugin.onCreate(context,savedInstanceState);\n        }\n    }\n\n    public void onStart(Context context) {\n        Set<String> set = PluginLists.keySet();\n        for (String key : set) {\n            Plugin plugin = PluginLists.get(key);\n            plugin.onStart(context);\n        }\n    }\n\n    public void onResume(Context context) {\n        Set<String> set = PluginLists.keySet();\n        for (String key : set) {\n            Plugin plugin = PluginLists.get(key);\n            plugin.onResume(context);\n        }\n    }\n\n    public void onPause(Context context) {\n        Set<String> set = PluginLists.keySet();\n        for (String key : set) {\n            Plugin plugin = PluginLists.get(key);\n            plugin.onPause(context);\n        }\n    }\n\n    public void onStop(Context context) {\n        Set<String> set = PluginLists.keySet();\n        for (String key : set) {\n            Plugin plugin = PluginLists.get(key);\n            plugin.onStop(context);\n        }\n    }\n\n    public void onRestart(Context context) {\n        Set<String> set = PluginLists.keySet();\n        for (String key : set) {\n            Plugin plugin = PluginLists.get(key);\n            plugin.onRestart(context);\n        }\n    }\n\n    public void onDestroy(Context context) {\n        Set<String> set = PluginLists.keySet();\n        for (String key : set) {\n            Plugin plugin = PluginLists.get(key);\n            plugin.onDestroy(context);\n        }\n    }\n\n    public void onNewIntent(Context context, Intent intent) {\n        Set<String> set = PluginLists.keySet();\n        for (String key : set) {\n            Plugin plugin = PluginLists.get(key);\n            plugin.onNewIntent(context,intent);\n        }\n    }\n\n    public void onActivityResult(Context context, int requestCode, int resultCode, Intent data) {\n        Set<String> set = PluginLists.keySet();\n        for (String key : set) {\n            Plugin plugin = PluginLists.get(key);\n            plugin.onActivityResult(context, requestCode, resultCode, data);\n        }\n    }\n\n    public void onRequestPermissionsResult(Context context, int requestCode, String[] permissions, int[] grantResults) {\n        Set<String> set = PluginLists.keySet();\n        for (String key : set) {\n            Plugin plugin = PluginLists.get(key);\n            plugin.onRequestPermissionsResult(context, requestCode, permissions, grantResults);\n        }\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/parse/plugin/PluginReflectApi.java",
    "content": "package com.bzai.gamesdk.common.utils_base.parse.plugin;\n\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport java.lang.reflect.Method;\n\n/**\n * Created by bzai.xiao on 2017/12/16\n * 反射api，通过反射实现插件功能的拨出，不影响代码\n */\n\npublic abstract class PluginReflectApi {\n\n    protected Object invoke(String methodName){\n        try {\n            Method method = this.getClass().getMethod(methodName);\n            method.setAccessible(true); //设置访问私有方法\n            return method.invoke(this);\n        } catch (Exception e) {\n            try {\n                Method method = this.getClass().getDeclaredMethod(methodName);\n                method.setAccessible(true);//设置访问私有方法\n                return method.invoke(this);\n            } catch (Exception e1) {\n                e1.printStackTrace();\n                LogUtils.debug_d(this.getClass().getSimpleName() + \",没有实现该方法： \" + methodName);\n                return null;\n            }\n        }\n    }\n\n    protected Object invoke(String methodName, Class<?>[] argTypes, Object[] args) {\n        try {\n            Method method = this.getClass().getMethod(methodName, argTypes);\n            method.setAccessible(true);//设置访问私有方法\n            return method.invoke(this, args);\n        } catch (Exception e) {\n            try {\n                Method method = this.getClass().getDeclaredMethod(methodName, argTypes);\n                method.setAccessible(true);//设置访问私有方法\n                return method.invoke(this, args);\n            } catch (Exception e1) {\n                e1.printStackTrace();\n                LogUtils.debug_d(this.getClass().getSimpleName() + \",没有实现该方法： \" + methodName);\n                return null;\n            }\n        }\n    }\n\n    protected Object invoke(Object mainObject, String methodName) {\n        Class<?> clazz = mainObject.getClass();\n        try {\n            Method method = clazz.getMethod(methodName);\n            method.setAccessible(true);//设置访问私有方法\n            return method.invoke(mainObject);\n        } catch (Exception e) {\n            try {\n                Method method = clazz.getDeclaredMethod(methodName);\n                method.setAccessible(true);//设置访问私有方法\n                return method.invoke(mainObject);\n            }catch (Exception e1){\n                e1.printStackTrace();\n                LogUtils.debug_d(mainObject.getClass().getSimpleName() + \",没有实现该方法： \" + methodName);\n                return null;\n            }\n        }\n    }\n\n    protected Object invoke(Object mainObject, String methodName, Class[] paramTypes, Object[] objects) {\n        Class<?> clazz = mainObject.getClass();\n        try {\n            Method method = clazz.getMethod(methodName, paramTypes);\n            method.setAccessible(true);//设置访问私有方法\n            return method.invoke(mainObject, objects);\n        } catch (Exception e) {\n            try {\n                Method method = clazz.getDeclaredMethod(methodName, paramTypes);\n                method.setAccessible(true);//设置访问私有方法\n                return method.invoke(mainObject, objects);\n            } catch (Exception e1) {\n                e1.printStackTrace();\n                LogUtils.debug_d(mainObject.getClass().getSimpleName() + \",没有实现该方法： \" + methodName);\n                return null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/parse/project/Project.java",
    "content": "package com.bzai.gamesdk.common.utils_base.parse.project;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport com.bzai.gamesdk.common.utils_base.interfaces.CallBackListener;\nimport com.bzai.gamesdk.common.utils_base.parse.plugin.PluginManager;\nimport com.bzai.gamesdk.common.utils_base.proguard.ProguardInterface;\n\nimport java.util.HashMap;\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc:\n *      基础项目工程共有的方法：\n *      初始化、登陆、支付...\n *      生命周期方法..\n */\n\npublic abstract class Project implements ProguardInterface {\n\n    /*****************************   Project 加载接口    **********************************/\n\n    public ProjectBeanList.ProjectBean projectBean;\n\n    private boolean hasInited;\n    protected synchronized void initProject() {\n        if (hasInited) {\n            return;\n        }\n        hasInited = true;\n    }\n\n    @Override\n    public String toString() {\n        return \"Project{\" + \"projectBean=\" + projectBean + \", hasInited=\" + hasInited + '}';\n    }\n\n\n    /*****************************  顶层 Project 功能接口：初始化、登陆、支付、退出    **********************************/\n\n\n    /**\n     * 初始化\n     */\n    public void init(Activity activity, String gameid, String gamekey, CallBackListener callBackListener) {\n\n    }\n\n    /**\n     * 登录\n     */\n    public void login(Activity activity, HashMap<String,Object> loginParams) {\n\n    }\n\n\n    /**\n     * 支付\n     */\n    public void pay(Activity activity, HashMap<String,Object> payParams, CallBackListener callBackListener) {\n\n    }\n\n    /**\n     * 切换账号\n     */\n    public void switchAccount(Activity activity){\n\n    }\n\n    /**\n     * 登出\n     */\n    public void logout(Activity activity) {\n\n    }\n\n\n    /**\n     * 退出\n     */\n    public void exit(Activity activity, CallBackListener callBackListener) {\n\n    }\n\n    /**\n     * 上报数据\n     */\n    public void reportData(Context context, HashMap<String,Object> dataMap){\n\n    }\n\n    /**\n     * 设置SDK账号监听\n     */\n    public void setAccountCallBackLister(CallBackListener callBackLister){\n\n    }\n\n    /**\n     * 显示SDK悬浮窗,将登录、支付等信息回调\n     */\n    public void showFloatView(Activity activity){}\n\n    /**\n     * 关闭SDK悬浮窗\n     */\n    public void dismissFloatView(Activity activity){}\n\n\n    /**\n     * 拓展接口，处理渠道的定制接口\n     */\n    public void extendFunction(Activity activity, int functionType, Object object, CallBackListener callBackListener){\n\n    }\n\n    /**\n     * 获取渠道ID\n     * @return\n     */\n    public String getChannelID(){\n        return null;\n    }\n\n\n    /*******************************  顶层 Project 生命周期接口 (目前实现各插件的生命周期)******************************/\n\n    public void onCreate(Activity activity, Bundle savedInstanceState) {\n        PluginManager.getInstance().onCreate(activity, savedInstanceState);\n    }\n\n    public void onStart(Activity activity) {\n        PluginManager.getInstance().onStart(activity);\n    }\n\n    public void onResume(Activity activity) {\n        PluginManager.getInstance().onResume(activity);\n    }\n\n    public void onPause(Activity activity) {\n        PluginManager.getInstance().onPause(activity);\n    }\n\n    public void onStop(Activity activity) {\n        PluginManager.getInstance().onStop(activity);\n    }\n\n    public void onRestart(Activity activity) {\n        PluginManager.getInstance().onRestart(activity);\n    }\n\n    public void onDestroy(Activity activity) {\n        PluginManager.getInstance().onDestroy(activity);\n    }\n\n    public void onNewIntent(Activity activity, Intent intent) {\n        PluginManager.getInstance().onNewIntent(activity,intent);\n    }\n\n    public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {\n        PluginManager.getInstance().onActivityResult(activity, requestCode, requestCode, data);\n    }\n\n    public void onRequestPermissionsResult(Activity activity, int requestCode, String[] permissions, int[] grantResults) {\n        PluginManager.getInstance().onRequestPermissionsResult(activity,requestCode,permissions,grantResults);\n    }\n}"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/parse/project/ProjectBeanList.java",
    "content": "package com.bzai.gamesdk.common.utils_base.parse.project;\n\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.proguard.ProguardObject;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport java.lang.reflect.Method;\nimport java.util.List;\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc: 项目实体类\n *\n * 只提供get方法，不提供set\n */\n\npublic class ProjectBeanList extends ProguardObject{\n\n    private List<ProjectBean> project; //注意解析的名字要跟文件一致，不然会导致解析错误\n\n    public List<ProjectBean> getProject() {\n        return project;\n    }\n\n    public void setProject(List<ProjectBean> project) {\n        this.project = project;\n    }\n\n    public static class ProjectBean extends ProguardObject {\n\n        private static final String TAG = \"ProjectBean\";\n        /**\n         * 反射插件的单例模式方法\n         * 返回的插件可能为空\n         *\n         * @return\n         */\n        public Project invokeGetInstance() {\n            Project p = null;\n            Class<?> glass = null;\n            if (TextUtils.isEmpty(class_name)) {\n                LogUtils.debug_w(TAG, \"invokeGetInstance: the class_name is blank\");\n                return p;\n            }\n            try {\n                glass = Class.forName(class_name);\n            } catch (ClassNotFoundException e) {\n                LogUtils.debug_w(TAG, \"invokeGetInstance: \" + \"do not find \" + class_name);\n            }\n            try {\n                //尝试调用getInstance\n                Method m = glass\n                        .getDeclaredMethod(\"getInstance\", new Class<?>[]{});\n                m.setAccessible(true);\n                p = (Project) m.invoke(null, new Object[]{});\n            } catch (NoSuchMethodException e1) {\n                //调用getInstance失败后，尝试new其对象\n                try {\n                    p = (Project) glass.newInstance();\n                } catch (Exception exception) {\n                    LogUtils.debug_w(TAG, \"glass.newInstance(): \" + \"do not find \" + class_name);\n                }\n            } catch (Exception exception) {\n                LogUtils.debug_w(TAG, \"glass.getInstance(): \" + \"do not find \" + class_name);\n            }\n\n            if (p == null) {\n                LogUtils.debug_w(TAG, class_name + \" is empty.\");\n            } else {\n                p.projectBean = this;\n            }\n            return p;\n        }\n\n        /**\n         * project_name : 项目名称\n         * class_name : 项目入口类\n         * description : 项目描述\n         * version : 版本信息\n         */\n\n        private String project_name;\n        private String class_name;\n        private String description;\n        private String version;\n\n        public String getProject_name() {\n            return project_name;\n        }\n\n        public void setProject_name(String plugin_name) {\n            this.project_name = plugin_name;\n        }\n\n        public String getClass_name() {\n            return class_name;\n        }\n\n        public void setClass_name(String class_name) {\n            this.class_name = class_name;\n        }\n\n        public String getDescription() {\n            return description;\n        }\n\n        public void setDescription(String description) {\n            this.description = description;\n        }\n\n        public String getVersion() {\n            return version;\n        }\n\n        public void setVersion(String version) {\n            this.version = version;\n        }\n\n        @Override\n        public String toString() {\n            return \"ProjectBean{\" +\n                    \" project_name='\" + project_name + '\\'' +\n                    \", class_name='\" + class_name + '\\'' +\n                    \", description='\" + description + '\\'' +\n                    \", version='\" + version + '\\'' +\n                    '}';\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/parse/project/ProjectManager.java",
    "content": "package com.bzai.gamesdk.common.utils_base.parse.project;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\nimport com.bzai.gamesdk.common.utils_base.utils.FileUtils;\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport java.util.HashMap;\nimport java.util.Set;\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc: 项目管理类\n */\npublic class ProjectManager {\n\n    private static final String TAG = \"ProjectManager\";\n    private static String PROJECT_CONFIG = \"Project_config.txt\";\n\n    private static Project project;\n    private HashMap<String, ProjectBeanList.ProjectBean> projectBeans = new HashMap<>();\n\n    /********************* 同步锁双重检测机制实现单例模式（懒加载）********************/\n    private volatile static ProjectManager projectManager;\n    public static ProjectManager init(Context context) {\n        if (projectManager == null) {\n            synchronized (ProjectManager.class) {\n                if (projectManager == null) {\n                    projectManager = new ProjectManager(context);\n                }\n            }\n        }\n        return projectManager;\n    }\n\n    public static ProjectManager getInstance() {\n        return projectManager;\n    }\n    /********************* 同步锁双重检测机制实现单例模式 ********************/\n\n    private ProjectManager(Context context) {\n        parse(context, PROJECT_CONFIG);\n    }\n\n    private void parse(Context context, String pluginFilePath) {\n        //从配置文件中，读取插件配置\n        StringBuilder projectContent = FileUtils.readAssetsFile(context, pluginFilePath);\n        String strProjectContent = String.valueOf(projectContent);\n\n        //进行解析\n        Gson gson = new Gson();\n        if (!TextUtils.isEmpty(strProjectContent)) {\n            try {\n\n                ProjectBeanList projectBeanList = gson.fromJson(strProjectContent, ProjectBeanList.class);\n                if (projectBeanList.getProject() != null && projectBeanList.getProject().size() != 0) {\n                    //如果解析结果无误，载入到listPluginBean中去\n                    for (ProjectBeanList.ProjectBean projectBean : projectBeanList.getProject()) {\n                        projectBeans.put(projectBean.getProject_name(), projectBean);\n                    }\n                    //打印解析结果\n                    LogUtils.debug_i(TAG, PROJECT_CONFIG +\" parse: \\n\" + projectBeans.toString());\n                } else {\n                    //解析结果出错\n                    LogUtils.e(TAG, PROJECT_CONFIG + \" parse error.\");\n                }\n\n            } catch (Exception e) {\n                //解析结果出错\n                LogUtils.e(TAG, PROJECT_CONFIG + \" parse exception.\");\n                e.printStackTrace();\n            }\n        }else {\n            LogUtils.e(TAG, PROJECT_CONFIG + \" parse is blank.\");\n        }\n\n    }\n\n\n    private boolean hasLoaded;\n    private static HashMap<String, Project> ProjectLists = new HashMap<String, Project>();\n\n\n    /**\n     * 加载所有的Project,可能存在多个项目\n     */\n    public synchronized void loadAllProjects() {\n        if (hasLoaded) {\n            return;\n        }\n        HashMap<String, ProjectBeanList.ProjectBean> entries = projectBeans;\n        Set<String> set = entries.keySet();\n        for (String key : set) {\n            loadProject(key);\n        }\n        LogUtils.debug_i(TAG, \"loadAllProjects:\" + ProjectLists.toString());\n        hasLoaded = true;\n    }\n\n\n    /**\n     * 加载一个项目，返回的Project可能为空\n     *\n     * @param projectName\n     * @return\n     * @throws RuntimeException\n     */\n    private Project loadProject(String projectName) throws RuntimeException {\n\n        // 1.查看从配置文件中读取的插件列表，是否存在此插件\n        HashMap<String, ProjectBeanList.ProjectBean> entries = projectBeans;\n        ProjectBeanList.ProjectBean projectBean = entries.get(projectName);\n        if (projectBean == null) {\n            LogUtils.debug_i(TAG, \"The project [\" +  projectName + \"] does not exists in \" + PROJECT_CONFIG);\n            return null;\n        }\n        Project project = null;\n        // 2.调用其单例模式方法\n        project = projectBean.invokeGetInstance();\n        if (project != null) {\n            // 3.反射初始化插件\n            project.initProject();\n            // 4.将已加载好的插件，添加到插件列表中去\n            ProjectLists.put(projectName, project);\n        }\n        return project;\n    }\n\n\n    /**\n     * 获取特定项目\n     * 可能为空\n     *\n     * @param projectName\n     * @return\n     */\n    public Project getProject(String projectName) {\n        if (!hasLoaded) {\n            LogUtils.debug_i(TAG, \"getProject: \" + projectName + \"Project not loaded yet\");\n            return null;\n        }\n        Project project = null;\n        HashMap<String, Project> entries = ProjectLists;\n        project = entries.get(projectName);\n        return project;\n    }\n\n\n    /**\n     * 加载当前的project项目\n     *\n     */\n    public void loadProject(){\n\n        ProjectBeanList.ProjectBean projectBean = projectBeans.get(\"project\");\n        if (projectBean == null){\n            LogUtils.debug_d(TAG, \"The project does not exists in \" + PROJECT_CONFIG);\n            return;\n        }\n\n        Project project = null;\n        project = projectBean.invokeGetInstance();\n        if (project != null){\n            project.initProject();\n            this.project = project;\n        }\n    }\n\n    /**\n     * 返回当前的project项目\n     * @return\n     */\n    public Project getProject(){\n        return project;\n    }\n\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/proguard/ProguardInterface.java",
    "content": "package com.bzai.gamesdk.common.utils_base.proguard;\n\n/**\n * Created by bzai on 2018/04/09.\n * 定义基础混淆接口\n */\n\npublic interface ProguardInterface {\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/proguard/ProguardObject.java",
    "content": "package com.bzai.gamesdk.common.utils_base.proguard;\n\n/**\n * Created by bzai on 2018/04/09.\n * 定义基础混淆对象\n */\npublic class ProguardObject {\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/ArrayUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\n/**\n * Array Utils\n * <ul>\n * <li>{@link #isEmpty(Object[])} is null or its length is 0</li>\n * <li>{@link #getLast(Object[], Object, Object, boolean)} get last element of the target element, before the first one\n * that match the target element front to back</li>\n * <li>{@link #getNext(Object[], Object, Object, boolean)} get next element of the target element, after the first one\n * that match the target element front to back</li>\n * <li>{@link #getLast(Object[], Object, boolean)}</li>\n * <li>{@link #getLast(int[], int, int, boolean)}</li>\n * <li>{@link #getLast(long[], long, long, boolean)}</li>\n * <li>{@link #getNext(Object[], Object, boolean)}</li>\n * <li>{@link #getNext(int[], int, int, boolean)}</li>\n * <li>{@link #getNext(long[], long, long, boolean)}</li>\n * </ul>\n * \n * @author <a href=\"http://www.trinea.cn\" target=\"_blank\">Trinea</a> 2011-10-24\n */\npublic class ArrayUtils {\n\n    private ArrayUtils() {\n        throw new AssertionError();\n    }\n\n    /**\n     * is null or its length is 0\n     * \n     * @param <V>\n     * @param sourceArray\n     * @return\n     */\n    public static <V> boolean isEmpty(V[] sourceArray) {\n        return (sourceArray == null || sourceArray.length == 0);\n    }\n\n    /**\n     * get last element of the target element, before the first one that match the target element front to back\n     * <ul>\n     * <li>if array is empty, return defaultValue</li>\n     * <li>if target element is not exist in array, return defaultValue</li>\n     * <li>if target element exist in array and its index is not 0, return the last element</li>\n     * <li>if target element exist in array and its index is 0, return the last one in array if isCircle is true, else\n     * return defaultValue</li>\n     * </ul>\n     * \n     * @param <V>\n     * @param sourceArray\n     * @param value value of target element\n     * @param defaultValue default return value\n     * @param isCircle whether is circle\n     * @return\n     */\n    public static <V> V getLast(V[] sourceArray, V value, V defaultValue, boolean isCircle) {\n        if (isEmpty(sourceArray)) {\n            return defaultValue;\n        }\n\n        int currentPosition = -1;\n        for (int i = 0; i < sourceArray.length; i++) {\n            if (ObjectUtils.isEquals(value, sourceArray[i])) {\n                currentPosition = i;\n                break;\n            }\n        }\n        if (currentPosition == -1) {\n            return defaultValue;\n        }\n\n        if (currentPosition == 0) {\n            return isCircle ? sourceArray[sourceArray.length - 1] : defaultValue;\n        }\n        return sourceArray[currentPosition - 1];\n    }\n\n    /**\n     * get next element of the target element, after the first one that match the target element front to back\n     * <ul>\n     * <li>if array is empty, return defaultValue</li>\n     * <li>if target element is not exist in array, return defaultValue</li>\n     * <li>if target element exist in array and not the last one in array, return the next element</li>\n     * <li>if target element exist in array and the last one in array, return the first one in array if isCircle is\n     * true, else return defaultValue</li>\n     * </ul>\n     * \n     * @param <V>\n     * @param sourceArray\n     * @param value value of target element\n     * @param defaultValue default return value\n     * @param isCircle whether is circle\n     * @return\n     */\n    public static <V> V getNext(V[] sourceArray, V value, V defaultValue, boolean isCircle) {\n        if (isEmpty(sourceArray)) {\n            return defaultValue;\n        }\n\n        int currentPosition = -1;\n        for (int i = 0; i < sourceArray.length; i++) {\n            if (ObjectUtils.isEquals(value, sourceArray[i])) {\n                currentPosition = i;\n                break;\n            }\n        }\n        if (currentPosition == -1) {\n            return defaultValue;\n        }\n\n        if (currentPosition == sourceArray.length - 1) {\n            return isCircle ? sourceArray[0] : defaultValue;\n        }\n        return sourceArray[currentPosition + 1];\n    }\n\n    /**\n     * @see {@link ArrayUtils#getLast(Object[], Object, Object, boolean)} defaultValue is null\n     */\n    public static <V> V getLast(V[] sourceArray, V value, boolean isCircle) {\n        return getLast(sourceArray, value, null, isCircle);\n    }\n\n    /**\n     * @see {@link ArrayUtils#getNext(Object[], Object, Object, boolean)} defaultValue is null\n     */\n    public static <V> V getNext(V[] sourceArray, V value, boolean isCircle) {\n        return getNext(sourceArray, value, null, isCircle);\n    }\n\n    /**\n     * @see {@link ArrayUtils#getLast(Object[], Object, Object, boolean)} Object is Long\n     */\n    public static long getLast(long[] sourceArray, long value, long defaultValue, boolean isCircle) {\n        if (sourceArray.length == 0) {\n            throw new IllegalArgumentException(\"The length of source array must be greater than 0.\");\n        }\n\n        Long[] array = ObjectUtils.transformLongArray(sourceArray);\n        return getLast(array, value, defaultValue, isCircle);\n\n    }\n\n    /**\n     * @see {@link ArrayUtils#getNext(Object[], Object, Object, boolean)} Object is Long\n     */\n    public static long getNext(long[] sourceArray, long value, long defaultValue, boolean isCircle) {\n        if (sourceArray.length == 0) {\n            throw new IllegalArgumentException(\"The length of source array must be greater than 0.\");\n        }\n\n        Long[] array = ObjectUtils.transformLongArray(sourceArray);\n        return getNext(array, value, defaultValue, isCircle);\n    }\n\n    /**\n     * @see {@link ArrayUtils#getLast(Object[], Object, Object, boolean)} Object is Integer\n     */\n    public static int getLast(int[] sourceArray, int value, int defaultValue, boolean isCircle) {\n        if (sourceArray.length == 0) {\n            throw new IllegalArgumentException(\"The length of source array must be greater than 0.\");\n        }\n\n        Integer[] array = ObjectUtils.transformIntArray(sourceArray);\n        return getLast(array, value, defaultValue, isCircle);\n\n    }\n\n    /**\n     * @see {@link ArrayUtils#getNext(Object[], Object, Object, boolean)} Object is Integer\n     */\n    public static int getNext(int[] sourceArray, int value, int defaultValue, boolean isCircle) {\n        if (sourceArray.length == 0) {\n            throw new IllegalArgumentException(\"The length of source array must be greater than 0.\");\n        }\n\n        Integer[] array = ObjectUtils.transformIntArray(sourceArray);\n        return getNext(array, value, defaultValue, isCircle);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/CodeUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLEncoder;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Created by bzai on 2018/04/09.\n *\n * 代码数据格式处理\n *\n */\n\npublic class CodeUtils {\n\n\n    public static String Unicode2GBK(String dataStr) {\n        int index = 0;\n        StringBuffer buffer = new StringBuffer();\n\n        int li_len = dataStr.length();\n        while (index < li_len) {\n            if (index >= li_len - 1\n                    || !\"\\\\u\".equals(dataStr.substring(index, index + 2))) {\n                buffer.append(dataStr.charAt(index));\n\n                index++;\n                continue;\n            }\n\n            String charStr = \"\";\n            charStr = dataStr.substring(index + 2, index + 6);\n\n            char letter = (char) Integer.parseInt(charStr, 16);\n\n            buffer.append(letter);\n            index += 6;\n        }\n\n        return buffer.toString();\n    }\n\n\n    /**\n     * 网络请求对Map<>数据拼接处理   </>\n     */\n    public static String appendParams(StringBuilder builder, Map<String, ?> params){\n\n        if (params == null || params.size() == 0) {\n            return builder.toString();\n        }\n\n        Set<String> keys = params.keySet();\n        String encoder = \"UTF-8\";\n        try {\n            boolean flag = true;\n            for (String key : keys) {\n                if (!flag) {\n                    builder.append(\"&\");\n                }\n                flag = false;\n                Object value = params.get(key);\n                builder.append(URLEncoder.encode(key, encoder));\n                builder.append(\"=\");\n                builder.append(value != null ? URLEncoder.encode(value.toString(), encoder) : \"\");\n            }\n\n            return builder.toString();\n        } catch (UnsupportedEncodingException e) {\n            return builder.toString();\n        }\n    }\n\n\n    /**\n     * 对传入的Kry值排序后，再拼接\n     * (不需要做编码转换)\n     */\n    public static String sortAndAppendParams(StringBuilder builder, HashMap<String,Object> params){\n\n        if (params == null || params.size() == 0) {\n            return \"\";\n        }\n\n        Collection<String> keySet = params.keySet();\n        List<String> list = new ArrayList<String>(keySet);\n\n        //对key键值按字典升序排序\n        Collections.sort(list);\n\n//        String encoder = \"UTF-8\";\n        try {\n            boolean flag = true;\n            for (String key : list) {\n                if (!flag) {\n                    builder.append(\"&\");\n                }\n                flag = false;\n                Object value = params.get(key);\n//                builder.append(URLEncoder.encode(key, encoder));\n                builder.append(key);\n                builder.append(\"=\");\n                builder.append(value != null ? value.toString() : \"\");\n//                builder.append(value != null ? URLEncoder.encode(value.toString(), encoder) : \"\");\n            }\n\n            return builder.toString();\n\n        } catch (Exception e) {\n\n            return \"\";\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/ContextUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\nimport android.Manifest;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.Signature;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.net.Uri;\nimport android.net.wifi.WifiInfo;\nimport android.net.wifi.WifiManager;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.telephony.TelephonyManager;\nimport android.text.TextUtils;\nimport android.util.DisplayMetrics;\nimport android.view.Display;\nimport android.view.WindowManager;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.reflect.Method;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.util.Enumeration;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * Created by bzai on 2018/4/16.\n * <p>\n * Desc:\n *\n *   用于获取系统的一些信息\n */\n\npublic class ContextUtils {\n\n    public static Object invokeTelephonyManagerMethod(String methodName,\n                                                      Context cxt) {\n        try {\n            Method m = Context.class.getMethod(\"getS\" + \"yste\" + \"mSer\"\n                    + \"vice\", new Class<?>[]{String.class});\n            Object phone = m.invoke(cxt, new Object[]{\"phone\"});\n\n            Method m2 = phone.getClass().getMethod(methodName,\n                    (Class<?>[]) null);\n            return m2.invoke(phone, (Object[]) null);\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    public static Object invokeTelephoneManagerMethod(String methodName,\n                                                      Class<?>[] paramTypes, Object[] params, Context cxt) {\n        try {\n            Method m = Context.class.getMethod(\"getS\" + \"yste\" + \"mSer\"\n                    + \"vice\", new Class<?>[]{String.class});\n            Object phone = m.invoke(cxt, new Object[]{\"phone\"});\n\n            Method m2 = phone.getClass().getMethod(methodName, paramTypes);\n            return m2.invoke(phone, (Object[]) params);\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    /**\n     * 返回设备类型\n     * @return\n     */\n    public static String getDeviceName(){\n        return \"android\";\n    }\n\n\n    public static String getVersionName(Context appContext) {\n        try {\n            PackageInfo pi = appContext.getPackageManager().getPackageInfo(\n                    appContext.getPackageName(), 0);\n            return pi.versionName;\n        } catch (PackageManager.NameNotFoundException e) {\n            return \"\";\n        }\n    }\n\n\n    public static final String UNKNOWN = \"unknown\";\n    public static final String WIFI = \"wifi\";\n    public static final String MOBILE = \"mobile\";\n\n    /***\n     * Return {@link #UNKNOWN} if the network type can not be accessed.\n     *\n     * @return 'wifi' or 'uninet' etc.\n     */\n    public static String getNetworkType(Context context) {\n        if (!checkPermission(context, Manifest.permission.ACCESS_NETWORK_STATE)) {\n            return UNKNOWN;\n        }\n        ConnectivityManager manager = (ConnectivityManager) context\n                .getSystemService(\"connectivity\");\n        NetworkInfo networkInfo = manager.getActiveNetworkInfo();\n        if (networkInfo == null) {\n            return UNKNOWN;\n        }\n        int net_type = networkInfo.getType();\n        if (net_type == ConnectivityManager.TYPE_MOBILE) {\n            networkInfo = manager.getNetworkInfo(0);\n            String netString = networkInfo.getExtraInfo();\n            if (TextUtils.isEmpty(netString)) {\n                return UNKNOWN;\n            } else {\n                return netString.length() > 10 ? netString.substring(0, 10)\n                        : netString;\n            }\n        } else {\n            return WIFI;\n        }\n    }\n\n    public static final float UI_DESIGN_DENSITY = 1.5F;\n\n    /**\n     * dip2px\n     *\n     * @param context\n     * @param dipValue\n     * @return\n     */\n    public static int dip2px(Context context, float dipValue) {\n        final float scale = context.getResources().getDisplayMetrics().density;\n        return (int) (dipValue * scale + 0.5f);\n    }\n\n    public static int px2dip(Context context, float dipValue) {\n        final float scale = context.getResources().getDisplayMetrics().density;\n        return (int) (dipValue / scale + 0.5f);\n    }\n\n    public static int fitToImage(Context context, float uiValue) {\n        final float scale = context.getResources().getDisplayMetrics().density;\n        return (int) ((uiValue / UI_DESIGN_DENSITY) * scale + 0.5f);// 因为图是按照480*800做的，密度为1.5\n    }\n\n    /**\n     * 拿到resolution as width X height\n     *\n     * @param context\n     * @return\n     */\n    public static String getResolutionAsString(Context context) {\n        WindowManager wm = (WindowManager) context\n                .getSystemService(Context.WINDOW_SERVICE);\n        Display display = wm.getDefaultDisplay();\n        int widthPixels = display.getWidth();\n        int heightPixels = display.getHeight();\n        return widthPixels < heightPixels ? widthPixels + \"X\" + heightPixels\n                : heightPixels + \"X\" + widthPixels;\n    }\n\n    /**\n     * Check whether the specified permission is granted to the current package.\n     *\n     * @param context\n     * @param permissionName The permission.\n     * @return True if granted, false otherwise.\n     */\n    public static boolean checkPermission(Context context, String permissionName) {\n        PackageManager packageManager = context.getPackageManager();\n        String pkgName = context.getPackageName();\n        return packageManager.checkPermission(permissionName, pkgName) == PackageManager.PERMISSION_GRANTED;\n    }\n\n    public static String getDeviceId(Context context) {\n        String imei = getIMEI(context);\n        if (!imei.equals(UNKNOWN)) {\n            return imei;\n        }\n        return getLocalMacAddress(context);\n    }\n\n    /**\n     * Get IMEI of the device. If it has no IMEI or no\n     * {@link Manifest.permission#READ_PHONE_STATE} permission or it is an\n     * emulator, {@link #UNKNOWN} will be returned.\n     */\n    public static String getIMEI(Context context) {\n        String id = null;\n        if (checkPermission(context, Manifest.permission.READ_PHONE_STATE)) {\n            id = (String) invokeTelephonyManagerMethod(\"getD\" + \"evi\" + \"ceId\",\n                    context);\n        }\n        if (TextUtils.isEmpty(id) || isZero(id)) {\n            return UNKNOWN;\n        }\n\n        return id;\n    }\n\n    /**\n     * Return the WIFI-MAC address.\n     *\n     * @return {@link #UNKNOWN} will be returned if any unexpected occurs.\n     */\n    public static String getLocalMacAddress(Context context) {\n        if (!checkPermission(context, Manifest.permission.ACCESS_WIFI_STATE)) {\n            return UNKNOWN;\n        }\n        WifiManager wifi = (WifiManager) context\n                .getSystemService(Context.WIFI_SERVICE);\n        WifiInfo info = wifi.getConnectionInfo();\n        if (null != info) {\n            String mac = info.getMacAddress();\n            if (!TextUtils.isEmpty(mac)) {\n                return mac;\n            }\n        }\n\n        return UNKNOWN;\n    }\n\n    // get cpu frequence\n    public static long getCpuFre() {\n        // #cat \"/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq\"\n        // /proc/cpuinfo\n\n        String cpuFreFile = \"/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq\";\n        return readLong(cpuFreFile);\n    }\n\n    private static long readLong(String file) {\n        RandomAccessFile raf = null;\n\n        try {\n            raf = getFile(file);\n            return Long.valueOf(raf.readLine());\n        } catch (Exception e) {\n            return 0;\n        } finally {\n            if (raf != null) {\n                try {\n                    raf.close();\n                } catch (IOException e) {\n                }\n            }\n        }\n    }\n\n    private static RandomAccessFile getFile(String filename) throws IOException {\n        File f = new File(filename);\n        return new RandomAccessFile(f, \"r\");\n    }\n\n    private static boolean isZero(String id) {\n        for (int i = 0; i < id.length(); i++) {\n            char index = id.charAt(i);\n            if (index != '0')\n                return false;\n        }\n        return true;\n    }\n\n    /**\n     * Return the current application's label.\n     */\n    public static String getLabel(Context context) {\n        try {\n            PackageManager pm = context.getPackageManager();\n            ApplicationInfo info = pm.getApplicationInfo(\n                    context.getPackageName(), 0);\n            String label = info.loadLabel(pm).toString();\n            return label;\n        } catch (PackageManager.NameNotFoundException e) {\n            // Should never happen\n        }\n        return null;\n    }\n\n    public final static int SIM_TYPE_CMCC = 1;\n    public final static int SIM_TYPE_UNICOM = 2;\n    public final static int SIM_TYPE_TELECOM = 3;\n    public final static int SIM_TYPE_UNKNOWN = -1;\n\n    /**\n     * 取sim卡所属运营商\n     *\n     * @return 如果判定不了，则返回{@link #SIM_TYPE_UNKNOWN}\n     * @see {@link #SIM_TYPE_CMCC}, {@link #SIM_TYPE_UNICOM},\n     * {@link #SIM_TYPE_TELECOM}\n     */\n    public static int getSimCardType(Context context) {\n        if (!checkPermission(context, Manifest.permission.READ_PHONE_STATE)) {\n            return SIM_TYPE_UNKNOWN;\n        }\n        int state = (Integer) invokeTelephonyManagerMethod(\"getSi\" + \"mState\",\n                context);\n        if (!(state == TelephonyManager.SIM_STATE_READY)) {\n            return SIM_TYPE_UNKNOWN;\n        }\n        String imsi = (String) invokeTelephonyManagerMethod(\"getSu\" + \"bscr\"\n                + \"ibe\" + \"rId\", context);\n        if (TextUtils.isEmpty(imsi)) {\n            return SIM_TYPE_UNKNOWN;\n        }\n        if (imsi.contains(\"46000\") || imsi.contains(\"46002\")\n                || imsi.contains(\"46007\")) {\n            return SIM_TYPE_CMCC;\n        } else if (imsi.contains(\"46001\") || imsi.contains(\"46006\")) {\n            return SIM_TYPE_UNICOM;\n        } else if (imsi.contains(\"46003\") || imsi.contains(\"46005\")) {\n            return SIM_TYPE_TELECOM;\n        }\n        return SIM_TYPE_UNKNOWN;\n    }\n\n    public static String getIMSI(Context context) {\n        String id = null;\n        if (checkPermission(context,\n                Manifest.permission.READ_PHONE_STATE)) {\n            id = (String) invokeTelephonyManagerMethod(\"getS\" + \"ubscr\"\n                    + \"iberId\", context);\n        }\n        if (TextUtils.isEmpty(id) || isZero(id)) {\n            return UNKNOWN;\n        }\n\n        return id;\n    }\n\n    /**\n     * Get IP address of the device.\n     *\n     * @return {@link #UNKNOWN} will be returned if any unexpected occurs.\n     */\n    public static String getLocalIpAddress() {\n        try {\n            Enumeration<NetworkInterface> en = NetworkInterface\n                    .getNetworkInterfaces();\n            if (en == null) {\n                return UNKNOWN;\n            }\n            while (en.hasMoreElements()) {\n                NetworkInterface intf = en.nextElement();\n                Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses();\n                if (enumIpAddr == null) {\n                    continue;\n                }\n\n                while (enumIpAddr.hasMoreElements()) {\n                    InetAddress inetAddress = enumIpAddr.nextElement();\n                    if (!inetAddress.isLoopbackAddress()) {\n                        return inetAddress.getHostAddress();\n                    }\n                }\n            }\n        } catch (SocketException ex) {\n        }\n        return UNKNOWN;\n    }\n\n    /**\n     * public static final int ORIENTATION_UNDEFINED = 0; public static final\n     * int ORIENTATION_PORTRAIT = 1; public static final int\n     * ORIENTATION_LANDSCAPE = 2; public static final int ORIENTATION_SQUARE =\n     * 3;\n     *\n     * @param context\n     * @return\n     */\n    public static int getOrientation(Context context) {\n        android.content.res.Configuration configuration = context\n                .getResources().getConfiguration();\n        return configuration.orientation;\n    }\n\n    /**\n     * Install the specified file.\n     */\n    public static void installPackage(Context context, File file) {\n        try {\n            Uri uri = Uri.fromFile(file);\n            Intent installIntent = new Intent(Intent.ACTION_VIEW);\n            installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            installIntent.setDataAndType(uri,\n                    \"application/vnd.android.package-archive\");\n            context.startActivity(installIntent);\n        } catch (Exception e) {\n            e.printStackTrace();\n            if (file != null) {\n                file.delete();\n            }\n        }\n    }\n\n    /**\n     * 是否是横屏\n     */\n    public static boolean isLandScape(Context activity) {\n        boolean b = false;\n        int orientation = activity.getResources().getConfiguration().orientation;\n        if (orientation == android.content.res.Configuration.ORIENTATION_LANDSCAPE) {\n            b = true;\n        }\n        return b;\n    }\n\n\n    /**\n     * 判断是否是手机号码\n     *\n     * @param phoneNum\n     * @return\n     */\n    public static boolean isMobileNO(String phoneNum) {\n        Pattern p = Pattern\n                .compile(\"^((13[0-9])|(15[^4,\\\\D])|(18[0,5-9]))\\\\d{8}$\");\n        String tempPhoneNum = phoneNum.replace(\" \", \"\");\n        if (tempPhoneNum.startsWith(\"+86\")) {\n            tempPhoneNum = tempPhoneNum.replace(\"+86\", \"\");\n        }\n        Matcher m = p.matcher(tempPhoneNum);\n        return m.matches();\n    }\n\n    /**\n     * 判断是否是手机设备\n     *\n     * @param context\n     * @return\n     */\n    public static boolean isPhoneDevice(Context context) {\n        boolean isPhoneDevice = true;\n        TelephonyManager telephony = (TelephonyManager) context\n                .getSystemService(Context.TELEPHONY_SERVICE);\n        int type = telephony.getPhoneType();\n        if (type == TelephonyManager.PHONE_TYPE_NONE) {\n            isPhoneDevice = false;\n        } else {\n            isPhoneDevice = true;\n        }\n        return isPhoneDevice;\n    }\n\n    /**\n     * 判断网络连接\n     *\n     * @param context\n     * @return\n     */\n    public static boolean isNetworkConnected(Context context) {\n        if (context != null) {\n            ConnectivityManager mConnectivityManager = (ConnectivityManager) context\n                    .getSystemService(Context.CONNECTIVITY_SERVICE);\n            NetworkInfo mNetworkInfo = mConnectivityManager\n                    .getActiveNetworkInfo();\n            if (mNetworkInfo != null) {\n                return mNetworkInfo.isAvailable();\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 判断SD card 是否可读\n     */\n    public static boolean isSdcardReadable(Context context) {\n        if (Build.VERSION.SDK_INT >= 19) {\n            // 如果是KitKat，先检查是否有read权限，如果没有，则直接返回false\n            if (!checkPermission(context,\n                    \"android.permission.READ_EXTERNAL_STORAGE\")) {\n                return false;\n            }\n        }\n        String state = Environment.getExternalStorageState();\n        return Environment.MEDIA_MOUNTED.equals(state);\n    }\n\n\n    /**\n     * 获取特定包名的签名\n     *\n     * @param context\n     * @param packageName\n     * @return\n     */\n    public static String md5Sign(Context context, String packageName) {\n\n        PackageManager pm = context.getPackageManager();\n        try {\n            PackageInfo info = pm.getPackageInfo(packageName,\n                    PackageManager.GET_SIGNATURES);\n            Signature[] signatures = info.signatures;\n            StringBuilder sb = new StringBuilder();\n            for (Signature signature : signatures) {\n                sb.append(signature.toCharsString());\n            }\n            return Md5Utils.getMd5(sb.toString());\n        } catch (PackageManager.NameNotFoundException e) {\n            e.printStackTrace();\n            LogUtils.debug_e(e.toString());\n        }\n        return null;\n    }\n\n    /**\n     * 拿到当前包的签名的MD5值\n     *\n     * @param context\n     * @return\n     */\n    public static String md5Sign(Context context) {\n        String packageName = context.getPackageName();\n        PackageManager pm = context.getPackageManager();\n        try {\n            PackageInfo info = pm.getPackageInfo(packageName,\n                    PackageManager.GET_SIGNATURES);\n            Signature[] signatures = info.signatures;\n            StringBuilder sb = new StringBuilder();\n            for (Signature signature : signatures) {\n                sb.append(signature.toCharsString());\n            }\n            return Md5Utils.getMd5(sb.toString());\n        } catch (PackageManager.NameNotFoundException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public static int getDensityInt(Context context) {\n        return (int) (getDensity(context) * 240);\n    }\n\n    private static float sDensity = -1.0f;\n    /**\n     * The logical density of the display.\n     */\n    public static float getDensity(Context context) {\n        if (sDensity < 0.0f) {\n            sDensity = context.getResources().getDisplayMetrics().density / 1.5f;\n        }\n        return sDensity;\n    }\n\n    public static double getPhysicalScreenSize(Context context) {\n        int[] screenWH = getResolution(context);\n        double screenSize = Math.sqrt(screenWH[0] * screenWH[0] + screenWH[1]\n                * screenWH[1]);\n        int densityInt = getDensityInt(context);\n        return screenSize / densityInt;\n    }\n\n    public static int[] getResolution(Context context) {\n        WindowManager wm = (WindowManager) context\n                .getSystemService(Context.WINDOW_SERVICE);\n        DisplayMetrics metrics = new DisplayMetrics();\n        wm.getDefaultDisplay().getMetrics(metrics);\n        return new int[] { metrics.widthPixels, metrics.heightPixels };\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/CryptUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\nimport java.security.Key;\n\nimport javax.crypto.Cipher;\n\n\n/**\n * Utility for encrypting and decrypting Strings.\n *\n * @author David\n */\npublic class CryptUtils {\n\n    protected static String DEFAULT_KEY = \"alwaysbe\";\n\n    private Cipher encryptCipher = null;\n\n    private Cipher decryptCipher = null;\n\n    private static final char[] sHexCharactors = new char[] { '0', '1', '2',\n            '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };\n\n    /**\n     * Convert byte array to string, byte[]{8, 16} will be converted to 0811.\n     *\n     * @param array\n     * @return\n     */\n    public static String toHexString(byte[] array) {\n        if (null == array) {\n            return null;\n        }\n        int length = array.length;\n        StringBuilder sb = new StringBuilder(length << 1);\n        for (int i = 0; i < length; i++) {\n            int b = array[i];\n\n            int low = b & 0xf;\n            b = b >> 4;\n            int high = b & 0xf;\n\n            sb.append(sHexCharactors[high]);\n            sb.append(sHexCharactors[low]);\n        }\n\n        return sb.toString();\n    }\n\n    /**\n     * Convert string to byte array.\n     *\n     * @param s\n     * @return\n     * @see #toHexString(byte[])\n     */\n    public static byte[] toByteArray(String s) {\n        if (null == s) {\n            return null;\n        }\n        String sub = s;\n        int len = sub.length();\n\n        byte[] array = new byte[len >> 1];\n        for (int i = 0, j = 0; i < len; i += 2, j++) {\n            char highChar = sub.charAt(i);\n            char lowChar = sub.charAt(i + 1);\n\n            String str = new String(new char[] { highChar, lowChar });\n\n            int value = Integer.parseInt(str, 16);\n            array[j] = (byte) value;\n        }\n        return array;\n    }\n\n    /**\n     * Construct an instance using the default encryption and decryption key.\n     */\n    public CryptUtils() {\n        this(DEFAULT_KEY);\n    }\n\n    /**\n     *\n     * @param keyStr\n     *            the key for encryption and decryption.\n     */\n    public CryptUtils(String keyStr) {\n        String keyString = keyStr;\n        if (null == keyString) {\n            keyString = DEFAULT_KEY;\n        }\n        Key key = null;\n        try {\n            key = getKey(keyString.getBytes());\n            encryptCipher = Cipher.getInstance(\"DES\");\n            encryptCipher.init(Cipher.ENCRYPT_MODE, key);\n\n            decryptCipher = Cipher.getInstance(\"DES\");\n            decryptCipher.init(Cipher.DECRYPT_MODE, key);\n        } catch (Exception e) {\n        }\n\n    }\n\n    /**\n     * Encrypt a byte array.\n     *\n     * @param arrB\n     * @return null if any exception is thrown.\n     */\n    public byte[] encrypt(byte[] arrB) {\n        try {\n            return encryptCipher.doFinal(arrB);\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    /**\n     * Encypt a string.\n     *\n     * @param strIn\n     * @return\n     */\n    public String encrypt(String strIn) {\n        if (null == strIn) {\n            return null;\n        }\n        byte[] data = strIn.getBytes();\n        byte[] encryptData = encrypt(data);\n        return toHexString(encryptData);\n    }\n\n    /**\n     * Decrypt a byte array.\n     *\n     * @param arrB\n     * @return null if any exception is thrown.\n     */\n    public byte[] decrypt(byte[] arrB) {\n        try {\n            return decryptCipher.doFinal(arrB);\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    /**\n     * Decrypt the string.\n     *\n     * @param strIn\n     * @return null if the string passed in is null or exception is thrown.\n     */\n    public String decrypt(String strIn) {\n        byte[] data = toByteArray(strIn);\n        if (null == data) {\n            return null;\n        }\n        byte[] decryptData = decrypt(data);\n        if (null == decryptData) {\n            return null;\n        }\n\n        return new String(decryptData);\n    }\n\n    private Key getKey(byte[] data) throws Exception {\n        byte[] keyArray = new byte[8];\n\n        for (int i = 0; i < data.length && i < keyArray.length; i++) {\n            keyArray[i] = data[i];\n        }\n        Key key = new javax.crypto.spec.SecretKeySpec(keyArray, \"DES\");\n        return key;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/DateUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * Created by bzai on 2018/6/29.\n * <p>\n * Desc:\n *\n *  日期工具类\n */\n\npublic class DateUtils {\n\n    /**\n     1，日期格式：String dateString = \"2017-06-20 10:30:30\" 对应的格式：String pattern = \"yyyy-MM-dd HH:mm:ss\";\n\n     2，日期格式：String dateString = \"2017-06-20\" 对应的格式：String pattern = \"yyyy-MM-dd\";\n\n     3，日期格式：String dateString = \"2017年06月20日 10时30分30秒 对应的格式：String pattern = \"yyyy年MM月dd日 HH时mm分ss秒\";\n\n\n     4，日期格式：String dateString = \"2017年06月20日\" 对应的格式：String pattern = \"yyyy年MM月dd日\";\n     */\n\n\n    /**\n     * 获取系统时间戳\n     * @return\n     */\n    public long getCurTimeLong(){\n        long time= System.currentTimeMillis();\n        return time;\n    }\n    /**\n     * 获取当前时间\n     * @param pattern\n     * @return\n     */\n    public static String getCurDate(String pattern){\n        SimpleDateFormat sDateFormat = new SimpleDateFormat(pattern);\n        return sDateFormat.format(new java.util.Date());\n    }\n\n    /**\n     * 时间戳转换成字符窜\n     * @param milSecond\n     * @param pattern\n     * @return\n     */\n    public static String getDateToString(long milSecond, String pattern) {\n        Date date = new Date(milSecond);\n        SimpleDateFormat format = new SimpleDateFormat(pattern);\n        return format.format(date);\n    }\n\n    /**\n     * 将字符串转为时间戳\n     * @param dateString\n     * @param pattern\n     * @return\n     */\n    public static long getStringToDate(String dateString, String pattern) {\n        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);\n        Date date = new Date();\n        try{\n            date = dateFormat.parse(dateString);\n        } catch(ParseException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n        return date.getTime();\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/FileUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport java.io.BufferedReader;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * File Utils\n * <ul>\n * Read or write file\n * <li>{@link #readFile(String, String)} read file</li>\n * <li>{@link #readFileToList(String, String)} read file to string list</li>\n * <li>{@link #writeFile(String, String, boolean)} write file from String</li>\n * <li>{@link #writeFile(String, String)} write file from String</li>\n * <li>{@link #writeFile(String, List, boolean)} write file from String List</li>\n * <li>{@link #writeFile(String, List)} write file from String List</li>\n * <li>{@link #writeFile(String, InputStream)} write file</li>\n * <li>{@link #writeFile(String, InputStream, boolean)} write file</li>\n * <li>{@link #writeFile(File, InputStream)} write file</li>\n * <li>{@link #writeFile(File, InputStream, boolean)} write file</li>\n * </ul>\n * <ul>\n * Operate file\n * <li>{@link #moveFile(File, File)} or {@link #moveFile(String, String)}</li>\n * <li>{@link #copyFile(String, String)}</li>\n * <li>{@link #getFileExtension(String)}</li>\n * <li>{@link #getFileName(String)}</li>\n * <li>{@link #getFileNameWithoutExtension(String)}</li>\n * <li>{@link #getFileSize(String)}</li>\n * <li>{@link #deleteFile(String)}</li>\n * <li>{@link #isFileExist(String)}</li>\n * <li>{@link #isFolderExist(String)}</li>\n * <li>{@link #makeFolders(String)}</li>\n * <li>{@link #makeDirs(String)}</li>\n * </ul>\n *\n * @author <a href=\"http://www.trinea.cn\" target=\"_blank\">Trinea</a> 2012-5-12\n */\npublic class FileUtils {\n\n    public final static String FILE_EXTENSION_SEPARATOR = \".\";\n\n    private FileUtils() {\n        throw new AssertionError();\n    }\n\n    /**\n     * 读取assets中的文件\n     *\n     * @param charsetName\n     * @return\n     */\n    public static StringBuilder readAssetsFile(Context context, String charsetName) {\n        StringBuilder fileContent = new StringBuilder(\"\");\n\n        BufferedReader reader = null;\n        try {\n            InputStreamReader is = new InputStreamReader(context.getAssets().open(charsetName));\n            reader = new BufferedReader(is);\n            String line = null;\n            while ((line = reader.readLine()) != null) {\n                if (!fileContent.toString().equals(\"\")) {\n                    fileContent.append(\"\\r\\n\");\n                }\n                fileContent.append(line);\n            }\n            return fileContent;\n        } catch (IOException e) {\n//            e.printStackTrace();\n            return fileContent;\n        } finally {\n            IOUtils.close(reader);\n        }\n    }\n\n    /**\n     * 读简单的文件\n     *\n     * @param file 文件对象\n     * @return 字符\n     */\n    public static String readSimplelyFile(File file) {\n        if (!file.exists()) {\n            return null;\n        }\n        ByteArrayOutputStream baos = null;\n        FileInputStream fis = null;\n        try {\n            fis = new FileInputStream(file);\n            baos = new ByteArrayOutputStream(4096);\n            byte[] b = new byte[1024];\n            int a = -1;\n            while ((a = fis.read(b)) != -1) {\n                baos.write(b, 0, a);\n            }\n            return baos.toString();\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            if (null != fis) {\n                try {\n                    fis.close();\n\n                } catch (IOException e) {\n                }\n            }\n            if (baos != null) {\n                try {\n                    baos.close();\n                } catch (IOException e) {\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 读简单的文件\n     *\n     * @param is\n     *            文件流\n     * @return 字符\n     */\n    public static String readSimplelyFile(InputStream is) {\n        if (is == null) {\n            return null;\n        }\n        ByteArrayOutputStream baos = null;\n        try {\n            baos = new ByteArrayOutputStream(4096);\n            byte[] b = new byte[1024];\n            int a = -1;\n            while ((a = is.read(b)) != -1) {\n                baos.write(b, 0, a);\n            }\n            return baos.toString();\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            if (null != is) {\n                try {\n                    is.close();\n\n                } catch (IOException e) {\n                }\n            }\n            if (baos != null) {\n                try {\n                    baos.close();\n                } catch (IOException e) {\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * read file\n     *\n     * @param filePath\n     * @param charsetName The name of a supported {@link java.nio.charset.Charset </code>charset<code>}\n     * @return if file not exist, return null, else return content of file\n     * @throws RuntimeException if an error occurs while operator BufferedReader\n     */\n    public static StringBuilder readFile(String filePath, String charsetName) {\n        File file = new File(filePath);\n        StringBuilder fileContent = new StringBuilder(\"\");\n        if (file == null || !file.isFile()) {\n            return null;\n        }\n\n        BufferedReader reader = null;\n        try {\n            InputStreamReader is = new InputStreamReader(new FileInputStream(file), charsetName);\n            reader = new BufferedReader(is);\n            String line = null;\n            while ((line = reader.readLine()) != null) {\n                if (!fileContent.toString().equals(\"\")) {\n                    fileContent.append(\"\\r\\n\");\n                }\n                fileContent.append(line);\n            }\n            return fileContent;\n        } catch (IOException e) {\n            throw new RuntimeException(\"IOException occurred. \", e);\n        } finally {\n            IOUtils.close(reader);\n        }\n    }\n\n    /**\n     * write file\n     *\n     * @param filePath\n     * @param content\n     * @param append   is append, if true, write to the end of file, else clear content of file and write into it\n     * @return return false if content is empty, true otherwise\n     * @throws RuntimeException if an error occurs while operator FileWriter\n     */\n    public static boolean writeFile(String filePath, String content, boolean append) {\n        if (StringUtils.isEmpty(content)) {\n            return false;\n        }\n\n        FileWriter fileWriter = null;\n        try {\n            makeDirs(filePath);\n            fileWriter = new FileWriter(filePath, append);\n            fileWriter.write(content);\n            return true;\n        } catch (IOException e) {\n            throw new RuntimeException(\"IOException occurred. \", e);\n        } finally {\n            IOUtils.close(fileWriter);\n        }\n    }\n\n    /**\n     * write file\n     *\n     * @param filePath\n     * @param contentList\n     * @param append      is append, if true, write to the end of file, else clear content of file and write into it\n     * @return return false if contentList is empty, true otherwise\n     * @throws RuntimeException if an error occurs while operator FileWriter\n     */\n    public static boolean writeFile(String filePath, List<String> contentList, boolean append) {\n        if (ListUtils.isEmpty(contentList)) {\n            return false;\n        }\n\n        FileWriter fileWriter = null;\n        try {\n            makeDirs(filePath);\n            fileWriter = new FileWriter(filePath, append);\n            int i = 0;\n            for (String line : contentList) {\n                if (i++ > 0) {\n                    fileWriter.write(\"\\r\\n\");\n                }\n                fileWriter.write(line);\n            }\n            return true;\n        } catch (IOException e) {\n            throw new RuntimeException(\"IOException occurred. \", e);\n        } finally {\n            IOUtils.close(fileWriter);\n        }\n    }\n\n    /**\n     * write file, the string will be written to the begin of the file\n     *\n     * @param filePath\n     * @param content\n     * @return\n     */\n    public static boolean writeFile(String filePath, String content) {\n        return writeFile(filePath, content, false);\n    }\n\n    /**\n     * write file, the string list will be written to the begin of the file\n     *\n     * @param filePath\n     * @param contentList\n     * @return\n     */\n    public static boolean writeFile(String filePath, List<String> contentList) {\n        return writeFile(filePath, contentList, false);\n    }\n\n    /**\n     * write file, the bytes will be written to the begin of the file\n     *\n     * @param filePath\n     * @param stream\n     * @return\n     * @see {@link #writeFile(String, InputStream, boolean)}\n     */\n    public static boolean writeFile(String filePath, InputStream stream) {\n        return writeFile(filePath, stream, false);\n    }\n\n    /**\n     * write file\n     *\n     * @param filePath   the file to be opened for writing.\n     * @param stream the input stream\n     * @param append if <code>true</code>, then bytes will be written to the end of the file rather than the beginning\n     * @return return true\n     * @throws RuntimeException if an error occurs while operator FileOutputStream\n     */\n    public static boolean writeFile(String filePath, InputStream stream, boolean append) {\n        return writeFile(filePath != null ? new File(filePath) : null, stream, append);\n    }\n\n    /**\n     * write file, the bytes will be written to the begin of the file\n     *\n     * @param file\n     * @param stream\n     * @return\n     * @see {@link #writeFile(File, InputStream, boolean)}\n     */\n    public static boolean writeFile(File file, InputStream stream) {\n        return writeFile(file, stream, false);\n    }\n\n    /**\n     * write file\n     *\n     * @param file   the file to be opened for writing.\n     * @param stream the input stream\n     * @param append if <code>true</code>, then bytes will be written to the end of the file rather than the beginning\n     * @return return true\n     * @throws RuntimeException if an error occurs while operator FileOutputStream\n     */\n    public static boolean writeFile(File file, InputStream stream, boolean append) {\n        OutputStream o = null;\n        try {\n            makeDirs(file.getAbsolutePath());\n            o = new FileOutputStream(file, append);\n            byte data[] = new byte[1024];\n            int length = -1;\n            while ((length = stream.read(data)) != -1) {\n                o.write(data, 0, length);\n            }\n            o.flush();\n            return true;\n        } catch (FileNotFoundException e) {\n            throw new RuntimeException(\"FileNotFoundException occurred. \", e);\n        } catch (IOException e) {\n            throw new RuntimeException(\"IOException occurred. \", e);\n        } finally {\n            IOUtils.close(o);\n            IOUtils.close(stream);\n        }\n    }\n\n    /**\n     * move file\n     *\n     * @param sourceFilePath\n     * @param destFilePath\n     */\n    public static void moveFile(String sourceFilePath, String destFilePath) {\n        if (TextUtils.isEmpty(sourceFilePath) || TextUtils.isEmpty(destFilePath)) {\n            throw new RuntimeException(\"Both sourceFilePath and destFilePath cannot be null.\");\n        }\n        moveFile(new File(sourceFilePath), new File(destFilePath));\n    }\n\n    /**\n     * move file\n     *\n     * @param srcFile\n     * @param destFile\n     */\n    public static void moveFile(File srcFile, File destFile) {\n        boolean rename = srcFile.renameTo(destFile);\n        if (!rename) {\n            copyFile(srcFile.getAbsolutePath(), destFile.getAbsolutePath());\n            deleteFile(srcFile.getAbsolutePath());\n        }\n    }\n\n    /**\n     * copy file\n     *\n     * @param sourceFilePath\n     * @param destFilePath\n     * @return\n     * @throws RuntimeException if an error occurs while operator FileOutputStream\n     */\n    public static boolean copyFile(String sourceFilePath, String destFilePath) {\n        InputStream inputStream = null;\n        try {\n            inputStream = new FileInputStream(sourceFilePath);\n        } catch (FileNotFoundException e) {\n            throw new RuntimeException(\"FileNotFoundException occurred. \", e);\n        }\n        return writeFile(destFilePath, inputStream);\n    }\n\n    /**\n     * read file to string list, a element of list is a line\n     *\n     * @param filePath\n     * @param charsetName The name of a supported {@link java.nio.charset.Charset </code>charset<code>}\n     * @return if file not exist, return null, else return content of file\n     * @throws RuntimeException if an error occurs while operator BufferedReader\n     */\n    public static List<String> readFileToList(String filePath, String charsetName) {\n        File file = new File(filePath);\n        List<String> fileContent = new ArrayList<String>();\n        if (file == null || !file.isFile()) {\n            return null;\n        }\n\n        BufferedReader reader = null;\n        try {\n            InputStreamReader is = new InputStreamReader(new FileInputStream(file), charsetName);\n            reader = new BufferedReader(is);\n            String line = null;\n            while ((line = reader.readLine()) != null) {\n                fileContent.add(line);\n            }\n            return fileContent;\n        } catch (IOException e) {\n            throw new RuntimeException(\"IOException occurred. \", e);\n        } finally {\n            IOUtils.close(reader);\n        }\n    }\n\n    /**\n     * get file name from path, not include suffix\n     * <p>\n     * <pre>\n     *      getFileNameWithoutExtension(null)               =   null\n     *      getFileNameWithoutExtension(\"\")                 =   \"\"\n     *      getFileNameWithoutExtension(\"   \")              =   \"   \"\n     *      getFileNameWithoutExtension(\"abc\")              =   \"abc\"\n     *      getFileNameWithoutExtension(\"a.mp3\")            =   \"a\"\n     *      getFileNameWithoutExtension(\"a.b.rmvb\")         =   \"a.b\"\n     *      getFileNameWithoutExtension(\"c:\\\\\")              =   \"\"\n     *      getFileNameWithoutExtension(\"c:\\\\a\")             =   \"a\"\n     *      getFileNameWithoutExtension(\"c:\\\\a.b\")           =   \"a\"\n     *      getFileNameWithoutExtension(\"c:a.txt\\\\a\")        =   \"a\"\n     *      getFileNameWithoutExtension(\"/home/admin\")      =   \"admin\"\n     *      getFileNameWithoutExtension(\"/home/admin/a.txt/b.mp3\")  =   \"b\"\n     * </pre>\n     *\n     * @param filePath\n     * @return file name from path, not include suffix\n     * @see\n     */\n    public static String getFileNameWithoutExtension(String filePath) {\n        if (StringUtils.isEmpty(filePath)) {\n            return filePath;\n        }\n\n        int extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR);\n        int filePosi = filePath.lastIndexOf(File.separator);\n        if (filePosi == -1) {\n            return (extenPosi == -1 ? filePath : filePath.substring(0, extenPosi));\n        }\n        if (extenPosi == -1) {\n            return filePath.substring(filePosi + 1);\n        }\n        return (filePosi < extenPosi ? filePath.substring(filePosi + 1, extenPosi) : filePath.substring(filePosi + 1));\n    }\n\n    /**\n     * get file name from path, include suffix\n     * <p>\n     * <pre>\n     *      getFileName(null)               =   null\n     *      getFileName(\"\")                 =   \"\"\n     *      getFileName(\"   \")              =   \"   \"\n     *      getFileName(\"a.mp3\")            =   \"a.mp3\"\n     *      getFileName(\"a.b.rmvb\")         =   \"a.b.rmvb\"\n     *      getFileName(\"abc\")              =   \"abc\"\n     *      getFileName(\"c:\\\\\")              =   \"\"\n     *      getFileName(\"c:\\\\a\")             =   \"a\"\n     *      getFileName(\"c:\\\\a.b\")           =   \"a.b\"\n     *      getFileName(\"c:a.txt\\\\a\")        =   \"a\"\n     *      getFileName(\"/home/admin\")      =   \"admin\"\n     *      getFileName(\"/home/admin/a.txt/b.mp3\")  =   \"b.mp3\"\n     * </pre>\n     *\n     * @param filePath\n     * @return file name from path, include suffix\n     */\n    public static String getFileName(String filePath) {\n        if (StringUtils.isEmpty(filePath)) {\n            return filePath;\n        }\n\n        int filePosi = filePath.lastIndexOf(File.separator);\n        return (filePosi == -1) ? filePath : filePath.substring(filePosi + 1);\n    }\n\n    /**\n     * get folder name from path\n     * <p>\n     * <pre>\n     *      getFolderName(null)               =   null\n     *      getFolderName(\"\")                 =   \"\"\n     *      getFolderName(\"   \")              =   \"\"\n     *      getFolderName(\"a.mp3\")            =   \"\"\n     *      getFolderName(\"a.b.rmvb\")         =   \"\"\n     *      getFolderName(\"abc\")              =   \"\"\n     *      getFolderName(\"c:\\\\\")              =   \"c:\"\n     *      getFolderName(\"c:\\\\a\")             =   \"c:\"\n     *      getFolderName(\"c:\\\\a.b\")           =   \"c:\"\n     *      getFolderName(\"c:a.txt\\\\a\")        =   \"c:a.txt\"\n     *      getFolderName(\"c:a\\\\b\\\\c\\\\d.txt\")    =   \"c:a\\\\b\\\\c\"\n     *      getFolderName(\"/home/admin\")      =   \"/home\"\n     *      getFolderName(\"/home/admin/a.txt/b.mp3\")  =   \"/home/admin/a.txt\"\n     * </pre>\n     *\n     * @param filePath\n     * @return\n     */\n    public static String getFolderName(String filePath) {\n\n        if (StringUtils.isEmpty(filePath)) {\n            return filePath;\n        }\n\n        int filePosi = filePath.lastIndexOf(File.separator);\n        return (filePosi == -1) ? \"\" : filePath.substring(0, filePosi);\n    }\n\n    /**\n     * get suffix of file from path\n     * <p>\n     * <pre>\n     *      getFileExtension(null)               =   \"\"\n     *      getFileExtension(\"\")                 =   \"\"\n     *      getFileExtension(\"   \")              =   \"   \"\n     *      getFileExtension(\"a.mp3\")            =   \"mp3\"\n     *      getFileExtension(\"a.b.rmvb\")         =   \"rmvb\"\n     *      getFileExtension(\"abc\")              =   \"\"\n     *      getFileExtension(\"c:\\\\\")              =   \"\"\n     *      getFileExtension(\"c:\\\\a\")             =   \"\"\n     *      getFileExtension(\"c:\\\\a.b\")           =   \"b\"\n     *      getFileExtension(\"c:a.txt\\\\a\")        =   \"\"\n     *      getFileExtension(\"/home/admin\")      =   \"\"\n     *      getFileExtension(\"/home/admin/a.txt/b\")  =   \"\"\n     *      getFileExtension(\"/home/admin/a.txt/b.mp3\")  =   \"mp3\"\n     * </pre>\n     *\n     * @param filePath\n     * @return\n     */\n    public static String getFileExtension(String filePath) {\n        if (StringUtils.isBlank(filePath)) {\n            return filePath;\n        }\n\n        int extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR);\n        int filePosi = filePath.lastIndexOf(File.separator);\n        if (extenPosi == -1) {\n            return \"\";\n        }\n        return (filePosi >= extenPosi) ? \"\" : filePath.substring(extenPosi + 1);\n    }\n\n    /**\n     * Creates the directory named by the trailing filename of this file, including the complete directory path required\n     * to create this directory. <br/>\n     * <br/>\n     * <ul>\n     * <strong>Attentions:</strong>\n     * <li>makeDirs(\"C:\\\\Users\\\\Trinea\") can only create users folder</li>\n     * <li>makeFolder(\"C:\\\\Users\\\\Trinea\\\\\") can create Trinea folder</li>\n     * </ul>\n     *\n     * @param filePath\n     * @return true if the necessary directories have been created or the target directory already exists, false one of\n     * the directories can not be created.\n     * <ul>\n     * <li>if {@link FileUtils#getFolderName(String)} return null, return false</li>\n     * <li>if target directory already exists, return true</li>\n     * <li>return {@link File#}</li>\n     * </ul>\n     */\n    public static boolean makeDirs(String filePath) {\n        String folderName = getFolderName(filePath);\n        if (StringUtils.isEmpty(folderName)) {\n            return false;\n        }\n\n        File folder = new File(folderName);\n        return (folder.exists() && folder.isDirectory()) ? true : folder.mkdirs();\n    }\n\n    /**\n     * @param filePath\n     * @return\n     * @see #makeDirs(String)\n     */\n    public static boolean makeFolders(String filePath) {\n        return makeDirs(filePath);\n    }\n\n    /**\n     * Indicates if this file represents a file on the underlying file system.\n     *\n     * @param filePath\n     * @return\n     */\n    public static boolean isFileExist(String filePath) {\n        if (StringUtils.isBlank(filePath)) {\n            return false;\n        }\n\n        File file = new File(filePath);\n        return (file.exists() && file.isFile());\n    }\n\n    /**\n     * Indicates if this file represents a directory on the underlying file system.\n     *\n     * @param directoryPath\n     * @return\n     */\n    public static boolean isFolderExist(String directoryPath) {\n        if (StringUtils.isBlank(directoryPath)) {\n            return false;\n        }\n\n        File dire = new File(directoryPath);\n        return (dire.exists() && dire.isDirectory());\n    }\n\n    /**\n     * delete file or directory\n     * <ul>\n     * <li>if path is null or empty, return true</li>\n     * <li>if path not exist, return true</li>\n     * <li>if path exist, delete recursion. return true</li>\n     * <ul>\n     *\n     * @param path\n     * @return\n     */\n    public static boolean deleteFile(String path) {\n        if (StringUtils.isBlank(path)) {\n            return true;\n        }\n\n        File file = new File(path);\n        if (!file.exists()) {\n            return true;\n        }\n        if (file.isFile()) {\n            return file.delete();\n        }\n        if (!file.isDirectory()) {\n            return false;\n        }\n        for (File f : file.listFiles()) {\n            if (f.isFile()) {\n                f.delete();\n            } else if (f.isDirectory()) {\n                deleteFile(f.getAbsolutePath());\n            }\n        }\n        return file.delete();\n    }\n\n    /**\n     * get file size\n     * <ul>\n     * <li>if path is null or empty, return -1</li>\n     * <li>if path exist and it is a file, return file size, else return -1</li>\n     * <ul>\n     *\n     * @param path\n     * @return returns the length of this file in bytes. returns -1 if the file does not exist.\n     */\n    public static long getFileSize(String path) {\n        if (StringUtils.isBlank(path)) {\n            return -1;\n        }\n\n        File file = new File(path);\n        return (file.exists() && file.isFile() ? file.length() : -1);\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/IOUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\nimport java.io.Closeable;\nimport java.io.IOException;\n\n/**\n * IO utils\n *\n * @author Vladislav Bauer\n */\n\npublic class IOUtils {\n\n    private IOUtils() {\n        throw new AssertionError();\n    }\n\n\n    /**\n     * Close closable object and wrap {@link IOException} with {@link RuntimeException}\n     * @param closeable closeable object\n     */\n    public static void close(Closeable closeable) {\n        if (closeable != null) {\n            try {\n                closeable.close();\n            } catch (IOException e) {\n                throw new RuntimeException(\"IOException occurred. \", e);\n            }\n        }\n    }\n\n    /**\n     * Close closable and hide possible {@link IOException}\n     * @param closeable closeable object\n     */\n    public static void closeQuietly(Closeable closeable) {\n        if (closeable != null) {\n            try {\n                closeable.close();\n            } catch (IOException e) {\n                // Ignored\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/JsonUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.HashMap;\nimport java.util.Iterator;\n\n/**\n * Created by bzai on 2018/04/09.\n */\n\npublic class JsonUtils {\n\n\n    /**\n     * 格式化Json数据\n     * @param jsonStr\n     * @return\n     */\n    public static String format(String jsonStr) {\n        int level = 0;\n        StringBuffer jsonForMatStr = new StringBuffer();\n        for(int i=0;i<jsonStr.length();i++){\n            char c = jsonStr.charAt(i);\n            if(level>0&&'\\n'==jsonForMatStr.charAt(jsonForMatStr.length()-1)){\n                jsonForMatStr.append(getLevelStr(level));\n            }\n            switch (c) {\n                case '{':\n                case '[':\n                    jsonForMatStr.append(c+\"\\n\");\n                    level++;\n                    break;\n                case ',':\n                    jsonForMatStr.append(c+\"\\n\");\n                    break;\n                case '}':\n                case ']':\n                    jsonForMatStr.append(\"\\n\");\n                    level--;\n                    jsonForMatStr.append(getLevelStr(level));\n                    jsonForMatStr.append(c);\n                    break;\n                default:\n                    jsonForMatStr.append(c);\n                    break;\n            }\n        }\n\n        return jsonForMatStr.toString();\n\n    }\n\n    private  static String getLevelStr(int level){\n        StringBuffer levelStr = new StringBuffer();\n        for(int levelI = 0;levelI<level ; levelI++){\n            levelStr.append(\"\\t\");\n        }\n        return levelStr.toString();\n    }\n\n\n\n    public static boolean isJson(String data){\n        try{\n            JSONObject dataJson = new JSONObject(data);\n            return true;\n        }catch(Exception e){\n            return false;\n        }\n    }\n\n    public static HashMap<String,Object> jsonStrToMap(String jsonStr){\n\n        HashMap<String, Object> mConfigs = new HashMap<>();\n        if (!jsonStr.equals(\"\")) {\n            try {\n                JSONObject jo = new JSONObject(jsonStr);\n                Iterator<?> keys = jo.keys();\n                while (keys.hasNext()) {\n                    String key = keys.next().toString();\n                    mConfigs.put(key, jo.getString(key));\n                }\n            } catch (JSONException e2) {\n                LogUtils.e(e2.toString());\n            }\n        }\n        return mConfigs;\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/ListUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * List Utils\n * \n * @author <a href=\"http://www.trinea.cn\" target=\"_blank\">Trinea</a> 2011-7-22\n */\npublic class ListUtils {\n\n    /** default join separator **/\n    public static final String DEFAULT_JOIN_SEPARATOR = \",\";\n\n    private ListUtils() {\n        throw new AssertionError();\n    }\n\n    /**\n     * get size of list\n     * \n     * <pre>\n     * getSize(null)   =   0;\n     * getSize({})     =   0;\n     * getSize({1})    =   1;\n     * </pre>\n     * \n     * @param <V>\n     * @param sourceList\n     * @return if list is null or empty, return 0, else return {@link List#size()}.\n     */\n    public static <V> int getSize(List<V> sourceList) {\n        return sourceList == null ? 0 : sourceList.size();\n    }\n\n    /**\n     * is null or its size is 0\n     * \n     * <pre>\n     * isEmpty(null)   =   true;\n     * isEmpty({})     =   true;\n     * isEmpty({1})    =   false;\n     * </pre>\n     * \n     * @param <V>\n     * @param sourceList\n     * @return if list is null or its size is 0, return true, else return false.\n     */\n    public static <V> boolean isEmpty(List<V> sourceList) {\n        return (sourceList == null || sourceList.size() == 0);\n    }\n\n    /**\n     * compare two list\n     * \n     * <pre>\n     * isEquals(null, null) = true;\n     * isEquals(new ArrayList&lt;String&gt;(), null) = false;\n     * isEquals(null, new ArrayList&lt;String&gt;()) = false;\n     * isEquals(new ArrayList&lt;String&gt;(), new ArrayList&lt;String&gt;()) = true;\n     * </pre>\n     * \n     * @param <V>\n     * @param actual\n     * @param expected\n     * @return\n     */\n    public static <V> boolean isEquals(ArrayList<V> actual, ArrayList<V> expected) {\n        if (actual == null) {\n            return expected == null;\n        }\n        if (expected == null) {\n            return false;\n        }\n        if (actual.size() != expected.size()) {\n            return false;\n        }\n\n        for (int i = 0; i < actual.size(); i++) {\n            if (!ObjectUtils.isEquals(actual.get(i), expected.get(i))) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * join list to string, separator is \",\"\n     * \n     * <pre>\n     * join(null)      =   \"\";\n     * join({})        =   \"\";\n     * join({a,b})     =   \"a,b\";\n     * </pre>\n     * \n     * @param list\n     * @return join list to string, separator is \",\". if list is empty, return \"\"\n     */\n    public static String join(List<String> list) {\n        return join(list, DEFAULT_JOIN_SEPARATOR);\n    }\n\n    /**\n     * join list to string\n     * \n     * <pre>\n     * join(null, '#')     =   \"\";\n     * join({}, '#')       =   \"\";\n     * join({a,b,c}, ' ')  =   \"abc\";\n     * join({a,b,c}, '#')  =   \"a#b#c\";\n     * </pre>\n     * \n     * @param list\n     * @param separator\n     * @return join list to string. if list is empty, return \"\"\n     */\n    public static String join(List<String> list, char separator) {\n        return join(list, new String(new char[] {separator}));\n    }\n\n    /**\n     * join list to string. if separator is null, use {@link #DEFAULT_JOIN_SEPARATOR}\n     * \n     * <pre>\n     * join(null, \"#\")     =   \"\";\n     * join({}, \"#$\")      =   \"\";\n     * join({a,b,c}, null) =   \"a,b,c\";\n     * join({a,b,c}, \"\")   =   \"abc\";\n     * join({a,b,c}, \"#\")  =   \"a#b#c\";\n     * join({a,b,c}, \"#$\") =   \"a#$b#$c\";\n     * </pre>\n     * \n     * @param list\n     * @param separator\n     * @return join list to string with separator. if list is empty, return \"\"\n     */\n    public static String join(List<String> list, String separator) {\n        return list == null ? \"\" : TextUtils.join(separator, list);\n    }\n\n    /**\n     * add distinct entry to list\n     * \n     * @param <V>\n     * @param sourceList\n     * @param entry\n     * @return if entry already exist in sourceList, return false, else add it and return true.\n     */\n    public static <V> boolean addDistinctEntry(List<V> sourceList, V entry) {\n        return (sourceList != null && !sourceList.contains(entry)) ? sourceList.add(entry) : false;\n    }\n\n    /**\n     * add all distinct entry to list1 from list2\n     * \n     * @param <V>\n     * @param sourceList\n     * @param entryList\n     * @return the count of entries be added\n     */\n    public static <V> int addDistinctList(List<V> sourceList, List<V> entryList) {\n        if (sourceList == null || isEmpty(entryList)) {\n            return 0;\n        }\n\n        int sourceCount = sourceList.size();\n        for (V entry : entryList) {\n            if (!sourceList.contains(entry)) {\n                sourceList.add(entry);\n            }\n        }\n        return sourceList.size() - sourceCount;\n    }\n\n    /**\n     * remove duplicate entries in list\n     * \n     * @param <V>\n     * @param sourceList\n     * @return the count of entries be removed\n     */\n    public static <V> int distinctList(List<V> sourceList) {\n        if (isEmpty(sourceList)) {\n            return 0;\n        }\n\n        int sourceCount = sourceList.size();\n        int sourceListSize = sourceList.size();\n        for (int i = 0; i < sourceListSize; i++) {\n            for (int j = (i + 1); j < sourceListSize; j++) {\n                if (sourceList.get(i).equals(sourceList.get(j))) {\n                    sourceList.remove(j);\n                    sourceListSize = sourceList.size();\n                    j--;\n                }\n            }\n        }\n        return sourceCount - sourceList.size();\n    }\n\n    /**\n     * add not null entry to list\n     * \n     * @param sourceList\n     * @param value\n     * @return <ul>\n     *         <li>if sourceList is null, return false</li>\n     *         <li>if value is null, return false</li>\n     *         <li>return {@link List#add(Object)}</li>\n     *         </ul>\n     */\n    public static <V> boolean addListNotNullValue(List<V> sourceList, V value) {\n        return (sourceList != null && value != null) ? sourceList.add(value) : false;\n    }\n\n    /**\n     * @see {@link ArrayUtils#getLast(Object[], Object, Object, boolean)} defaultValue is null, isCircle is true\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <V> V getLast(List<V> sourceList, V value) {\n        return (sourceList == null) ? null : (V)ArrayUtils.getLast(sourceList.toArray(), value, true);\n    }\n\n    /**\n     * @see {@link ArrayUtils#getNext(Object[], Object, Object, boolean)} defaultValue is null, isCircle is true\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <V> V getNext(List<V> sourceList, V value) {\n        return (sourceList == null) ? null : (V)ArrayUtils.getNext(sourceList.toArray(), value, true);\n    }\n\n    /**\n     * invert list\n     * \n     * @param <V>\n     * @param sourceList\n     * @return\n     */\n    public static <V> List<V> invertList(List<V> sourceList) {\n        if (isEmpty(sourceList)) {\n            return sourceList;\n        }\n\n        List<V> invertList = new ArrayList<V>(sourceList.size());\n        for (int i = sourceList.size() - 1; i >= 0; i--) {\n            invertList.add(sourceList.get(i));\n        }\n        return invertList;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/LogUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\n\nimport com.bzai.gamesdk.common.utils_base.frame.logger.AndroidLogAdapter;\nimport com.bzai.gamesdk.common.utils_base.frame.logger.FormatStrategy;\nimport com.bzai.gamesdk.common.utils_base.frame.logger.Logger;\nimport com.bzai.gamesdk.common.utils_base.frame.logger.PrettyFormatStrategy;\n\n/**\n * Created by bzai on 2018/04/09.\n */\n\npublic class LogUtils {\n\n    public static final String LOG_TAG = \"SYSDK\";\n\n    public static boolean DEBUG_VERSION = false;\n\n    /**\n     * 设置日志开关模式\n     * @param isDebugLog\n     */\n    public static void setDebugLogModel(boolean isDebugLog){\n        DEBUG_VERSION = isDebugLog;\n    }\n\n    static {\n\n        FormatStrategy formatStrategy = null;\n        if (DEBUG_VERSION) {\n            formatStrategy = PrettyFormatStrategy.newBuilder()\n                    .showThreadInfo(true)\n                    .methodCount(5)\n                    .tag(LOG_TAG)\n                    .build();\n        } else {\n            formatStrategy = PrettyFormatStrategy.newBuilder()\n                    .methodCount(5)\n                    .methodOffset(2)\n                    .showThreadInfo(false)\n                    .tag(LOG_TAG)\n                    .build();\n        }\n        Logger.addLogAdapter(new AndroidLogAdapter(formatStrategy));\n    }\n\n    private LogUtils() {\n\n    }\n\n\n//    --------------------------------------------以下事件输出不区分环境------------------------------------------\n\n\n    public static void i(Object o) {\n        i(null, String.valueOf(o));\n    }\n\n    public static void i(String tag, Object o) {\n        if (tag == null)\n            Logger.i(String.valueOf(o));\n        else\n            Logger.t(tag).i(String.valueOf(o));\n    }\n\n    public static void d(Object o) {\n        d(null, o);\n    }\n\n    public static void d(String tag, Object o) {\n        if (tag == null)\n            Logger.d(o);\n        else\n            Logger.t(tag).d(o);\n    }\n\n\n    public static void w(Object o) {\n        w(null, String.valueOf(o));\n    }\n\n    public static void w(String tag, Object o) {\n        if (tag == null)\n            Logger.w(String.valueOf(o));\n        else\n            Logger.t(tag).w(String.valueOf(o));\n    }\n\n    public static void e(Object o) {\n        e(null, String.valueOf(o));\n    }\n\n    public static void e(String tag, Object o) {\n        if (tag == null)\n            Logger.e(String.valueOf(o));\n        else\n            Logger.t(tag).e(String.valueOf(o));\n    }\n\n    public static void json(String json) {\n        json(null, json);\n    }\n\n    public static void json(String tag, String json) {\n        if (tag == null)\n            Logger.json(json);\n        else\n            Logger.t(tag).json(json);\n    }\n\n\n//    --------------------------------------------以下事件仅在debug模式下进行输出------------------------------------------\n\n    public static void debug_i(Object o) {\n        if (DEBUG_VERSION && o != null) {\n            debug_i(null, String.valueOf(o));\n        }\n    }\n\n    public static void debug_i(String tag, Object o) {\n        if (DEBUG_VERSION && o != null) {\n            if (tag == null)\n                Logger.i(String.valueOf(o));\n            else\n                Logger.t(tag).i(String.valueOf(o));\n        }\n    }\n\n    public static void debug_d(Object o) {\n        if (DEBUG_VERSION && o != null) {\n            debug_d(null, o);\n        }\n    }\n\n    public static void debug_d(String tag, Object o) {\n        if (DEBUG_VERSION && o != null) {\n            if (tag == null)\n                Logger.d(o);\n            else\n                Logger.t(tag).d(o);\n        }\n    }\n\n\n    public static void debug_w(Object o) {\n        if (DEBUG_VERSION && o != null) {\n            debug_w(null, String.valueOf(o));\n        }\n    }\n\n    public static void debug_w(String tag, Object o) {\n        if (DEBUG_VERSION && o != null) {\n            if (tag == null)\n                Logger.w(String.valueOf(o));\n            else\n                Logger.t(tag).w(String.valueOf(o));\n        }\n    }\n\n    public static void debug_e(Object o) {\n        if (DEBUG_VERSION && o != null) {\n            debug_e(null, String.valueOf(o));\n        }\n    }\n\n    public static void debug_e(String tag, Object o) {\n        if (DEBUG_VERSION && o != null) {\n            if (tag == null)\n                Logger.e(String.valueOf(o));\n            else\n                Logger.t(tag).e(String.valueOf(o));\n        }\n    }\n\n    public static void debug_json(String json) {\n        if (DEBUG_VERSION && json != null) {\n            debug_json(null, json);\n        }\n    }\n\n    public static void debug_json(String tag, String json) {\n        if (DEBUG_VERSION && json != null) {\n            if (tag == null)\n                Logger.json(json);\n            else\n                Logger.t(tag).json(json);\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/Md5Utils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\nimport java.io.UnsupportedEncodingException;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\npublic class Md5Utils {\n\n\tpublic static String getMd5(String str) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\ttry {\n\t\t\tMessageDigest md = MessageDigest.getInstance(\"MD5\");\n\t\t\tmd.update(str.getBytes(\"UTF-8\"));\n\t\t\tbyte[] hash = md.digest();\n\t\t\tString s;\n\t\t\tfor (byte b : hash) {\n\t\t\t\ts = Integer.toHexString(0xff & b);\n\t\t\t\tif (s.length() == 1) {\n\t\t\t\t\tsb.append(\"0\");\n\t\t\t\t}\n\t\t\t\tsb.append(s);\n\t\t\t}\n\t\t} catch (NoSuchAlgorithmException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\n\t/**\n\t * 对于MD5加密后的字符，做绝对值，低于2位的补0处理\n\t *\n\t * @param target\n\t *            要加密的字符\n\t * @return md5加密后的字符\n\t */\n\tpublic static String md5(String target) {\n\t\ttry {\n\t\t\tMessageDigest md = MessageDigest.getInstance(\"MD5\");\n\t\t\tbyte[] md5 = md.digest(target.getBytes());\n\t\t\tStringBuffer sb = new StringBuffer();\n\t\t\tString part = null;\n\t\t\tfor (int i = 0; i < md5.length; i++) {\n\t\t\t\tpart = Integer.toHexString(md5[i] & 0xFF);\n\t\t\t\tif (part.length() == 1) {\n\t\t\t\t\tpart = \"0\" + part;\n\t\t\t\t}\n\t\t\t\tsb.append(part);\n\t\t\t}\n\t\t\treturn sb.toString();\n\t\t} catch (NoSuchAlgorithmException ex) {\n\t\t}\n\t\treturn null;\n\t}\n\n\n\tpublic final static String MD5(String s) {\n\t\tchar hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n\t\ttry {\n\t\t\tbyte[] btInput = s.getBytes();\n\t\t\t// 获得MD5摘要算法的 MessageDigest 对象\n\t\t\tMessageDigest mdInst = MessageDigest.getInstance(\"MD5\");\n\t\t\t// 使用指定的字节更新摘要\n\t\t\tmdInst.update(btInput);\n\t\t\t// 获得密文\n\t\t\tbyte[] md = mdInst.digest();\n\t\t\t// 把密文转换成十六进制的字符串形式\n\t\t\tint j = md.length;\n\t\t\tchar str[] = new char[j * 2];\n\t\t\tint k = 0;\n\t\t\tfor (int i = 0; i < j; i++) {\n\t\t\t\tbyte byte0 = md[i];\n\t\t\t\tstr[k++] = hexDigits[byte0 >>> 4 & 0xf];\n\t\t\t\tstr[k++] = hexDigits[byte0 & 0xf];\n\t\t\t}\n\t\t\treturn new String(str);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\treturn null;\n\t\t}\n\t}\n\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/ObjectUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\n\nimport java.lang.reflect.Field;\nimport java.util.HashMap;\n\n\n/**\n * Object Utils\n * \n * @author <a href=\"http://www.trinea.cn\" target=\"_blank\">Trinea</a> 2011-10-24\n */\npublic class ObjectUtils {\n\n    private ObjectUtils() {\n        throw new AssertionError();\n    }\n\n    /**\n     * compare two object\n     * \n     * @param actual\n     * @param expected\n     * @return <ul>\n     *         <li>if both are null, return true</li>\n     *         <li>return actual.{@link Object#equals(Object)}</li>\n     *         </ul>\n     */\n    public static boolean isEquals(Object actual, Object expected) {\n        return actual == expected || (actual == null ? expected == null : actual.equals(expected));\n    }\n\n    /**\n     * null Object to empty string\n     * \n     * <pre>\n     * nullStrToEmpty(null) = &quot;&quot;;\n     * nullStrToEmpty(&quot;&quot;) = &quot;&quot;;\n     * nullStrToEmpty(&quot;aa&quot;) = &quot;aa&quot;;\n     * </pre>\n     * \n     * @param str\n     * @return\n     */\n    public static String nullStrToEmpty(Object str) {\n        return (str == null ? \"\" : (str instanceof String ? (String)str : str.toString()));\n    }\n\n    /**\n     * convert long array to Long array\n     * \n     * @param source\n     * @return\n     */\n    public static Long[] transformLongArray(long[] source) {\n        Long[] destin = new Long[source.length];\n        for (int i = 0; i < source.length; i++) {\n            destin[i] = source[i];\n        }\n        return destin;\n    }\n\n    /**\n     * convert Long array to long array\n     * \n     * @param source\n     * @return\n     */\n    public static long[] transformLongArray(Long[] source) {\n        long[] destin = new long[source.length];\n        for (int i = 0; i < source.length; i++) {\n            destin[i] = source[i];\n        }\n        return destin;\n    }\n\n    /**\n     * convert int array to Integer array\n     * \n     * @param source\n     * @return\n     */\n    public static Integer[] transformIntArray(int[] source) {\n        Integer[] destin = new Integer[source.length];\n        for (int i = 0; i < source.length; i++) {\n            destin[i] = source[i];\n        }\n        return destin;\n    }\n\n    /**\n     * convert Integer array to int array\n     * \n     * @param source\n     * @return\n     */\n    public static int[] transformIntArray(Integer[] source) {\n        int[] destin = new int[source.length];\n        for (int i = 0; i < source.length; i++) {\n            destin[i] = source[i];\n        }\n        return destin;\n    }\n\n    /**\n     * compare two object\n     * <ul>\n     * <strong>About result</strong>\n     * <li>if v1 > v2, return 1</li>\n     * <li>if v1 = v2, return 0</li>\n     * <li>if v1 < v2, return -1</li>\n     * </ul>\n     * <ul>\n     * <strong>About rule</strong>\n     * <li>if v1 is null, v2 is null, then return 0</li>\n     * <li>if v1 is null, v2 is not null, then return -1</li>\n     * <li>if v1 is not null, v2 is null, then return 1</li>\n     * <li>return v1.{@link Comparable#compareTo(Object)}</li>\n     * </ul>\n     * \n     * @param v1\n     * @param v2\n     * @return\n     */\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    public static <V> int compare(V v1, V v2) {\n        return v1 == null ? (v2 == null ? 0 : -1) : (v2 == null ? 1 : ((Comparable)v1).compareTo(v2));\n    }\n\n\n    /**\n     * 实体对象转成Map\n     * @param obj 实体对象\n     * @return Map\n     *\n     * 注意这种会多两个字段：\n     *\n     *  serialVersionUID=8987518414635299559 序列化的\n     *  $change=null 发现change是AS中instant run工具生成出来的,关掉就好了\n     */\n    public static HashMap<String, Object> objectToMap(Object obj) {\n\n        HashMap<String, Object> map = new HashMap<>();\n        if (obj == null) {\n            return map;\n        }\n        Class clazz = obj.getClass();\n        Field[] fields = clazz.getDeclaredFields();\n        try {\n            for (Field field : fields) {\n                field.setAccessible(true);\n                map.put(field.getName(), field.get(obj));\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        //需要处理下这两个key\n        if (map.containsKey(\"serialVersionUID\")){\n            map.remove(\"serialVersionUID\");\n        }\n\n        if (map.containsKey(\"$change\")){\n            map.remove(\"$change\");\n        }\n\n        return map;\n    }\n\n\n\n\n\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_base/utils/StringUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_base.utils;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLEncoder;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * String Utils\n * \n * @author <a href=\"http://www.trinea.cn\" target=\"_blank\">Trinea</a> 2011-7-22\n */\npublic class StringUtils {\n\n    private StringUtils() {\n        throw new AssertionError();\n    }\n\n    /**\n     * is null or its length is 0 or it is made by space\n     * \n     * <pre>\n     * isBlank(null) = true;\n     * isBlank(&quot;&quot;) = true;\n     * isBlank(&quot;  &quot;) = true;\n     * isBlank(&quot;a&quot;) = false;\n     * isBlank(&quot;a &quot;) = false;\n     * isBlank(&quot; a&quot;) = false;\n     * isBlank(&quot;a b&quot;) = false;\n     * </pre>\n     * \n     * @param str\n     * @return if string is null or its size is 0 or it is made by space, return true, else return false.\n     */\n    public static boolean isBlank(String str) {\n        return (str == null || str.trim().length() == 0);\n    }\n\n    /**\n     * is null or its length is 0\n     * \n     * <pre>\n     * isEmpty(null) = true;\n     * isEmpty(&quot;&quot;) = true;\n     * isEmpty(&quot;  &quot;) = false;\n     * </pre>\n     * \n     * @param str\n     * @return if string is null or its size is 0, return true, else return false.\n     */\n    public static boolean isEmpty(CharSequence str) {\n        return (str == null || str.length() == 0);\n    }\n\n    /**\n     * compare two string\n     * \n     * @param actual\n     * @param expected\n     * @return\n     * @see ObjectUtils#isEquals(Object, Object)\n     */\n    public static boolean isEquals(String actual, String expected) {\n        return ObjectUtils.isEquals(actual, expected);\n    }\n\n    /**\n     * get length of CharSequence\n     * \n     * <pre>\n     * length(null) = 0;\n     * length(\\\"\\\") = 0;\n     * length(\\\"abc\\\") = 3;\n     * </pre>\n     * \n     * @param str\n     * @return if str is null or empty, return 0, else return {@link CharSequence#length()}.\n     */\n    public static int length(CharSequence str) {\n        return str == null ? 0 : str.length();\n    }\n\n    /**\n     * null Object to empty string\n     * \n     * <pre>\n     * nullStrToEmpty(null) = &quot;&quot;;\n     * nullStrToEmpty(&quot;&quot;) = &quot;&quot;;\n     * nullStrToEmpty(&quot;aa&quot;) = &quot;aa&quot;;\n     * </pre>\n     * \n     * @param str\n     * @return\n     */\n    public static String nullStrToEmpty(Object str) {\n        return (str == null ? \"\" : (str instanceof String ? (String)str : str.toString()));\n    }\n\n    /**\n     * capitalize first letter\n     * \n     * <pre>\n     * capitalizeFirstLetter(null)     =   null;\n     * capitalizeFirstLetter(\"\")       =   \"\";\n     * capitalizeFirstLetter(\"2ab\")    =   \"2ab\"\n     * capitalizeFirstLetter(\"a\")      =   \"A\"\n     * capitalizeFirstLetter(\"ab\")     =   \"Ab\"\n     * capitalizeFirstLetter(\"Abc\")    =   \"Abc\"\n     * </pre>\n     * \n     * @param str\n     * @return\n     */\n    public static String capitalizeFirstLetter(String str) {\n        if (isEmpty(str)) {\n            return str;\n        }\n\n        char c = str.charAt(0);\n        return (!Character.isLetter(c) || Character.isUpperCase(c)) ? str : new StringBuilder(str.length())\n                .append(Character.toUpperCase(c)).append(str.substring(1)).toString();\n    }\n\n    /**\n     * encoded in utf-8\n     * \n     * <pre>\n     * utf8Encode(null)        =   null\n     * utf8Encode(\"\")          =   \"\";\n     * utf8Encode(\"aa\")        =   \"aa\";\n     * utf8Encode(\"啊啊啊啊\")   = \"%E5%95%8A%E5%95%8A%E5%95%8A%E5%95%8A\";\n     * </pre>\n     * \n     * @param str\n     * @return\n     * @throws UnsupportedEncodingException if an error occurs\n     */\n    public static String utf8Encode(String str) {\n        if (!isEmpty(str) && str.getBytes().length != str.length()) {\n            try {\n                return URLEncoder.encode(str, \"UTF-8\");\n            } catch (UnsupportedEncodingException e) {\n                throw new RuntimeException(\"UnsupportedEncodingException occurred. \", e);\n            }\n        }\n        return str;\n    }\n\n    /**\n     * encoded in utf-8, if exception, return defultReturn\n     * \n     * @param str\n     * @param defultReturn\n     * @return\n     */\n    public static String utf8Encode(String str, String defultReturn) {\n        if (!isEmpty(str) && str.getBytes().length != str.length()) {\n            try {\n                return URLEncoder.encode(str, \"UTF-8\");\n            } catch (UnsupportedEncodingException e) {\n                return defultReturn;\n            }\n        }\n        return str;\n    }\n\n    /**\n     * get innerHtml from href\n     * \n     * <pre>\n     * getHrefInnerHtml(null)                                  = \"\"\n     * getHrefInnerHtml(\"\")                                    = \"\"\n     * getHrefInnerHtml(\"mp3\")                                 = \"mp3\";\n     * getHrefInnerHtml(\"&lt;a innerHtml&lt;/a&gt;\")                    = \"&lt;a innerHtml&lt;/a&gt;\";\n     * getHrefInnerHtml(\"&lt;a&gt;innerHtml&lt;/a&gt;\")                    = \"innerHtml\";\n     * getHrefInnerHtml(\"&lt;a&lt;a&gt;innerHtml&lt;/a&gt;\")                    = \"innerHtml\";\n     * getHrefInnerHtml(\"&lt;a href=\"baidu.com\"&gt;innerHtml&lt;/a&gt;\")               = \"innerHtml\";\n     * getHrefInnerHtml(\"&lt;a href=\"baidu.com\" title=\"baidu\"&gt;innerHtml&lt;/a&gt;\") = \"innerHtml\";\n     * getHrefInnerHtml(\"   &lt;a&gt;innerHtml&lt;/a&gt;  \")                           = \"innerHtml\";\n     * getHrefInnerHtml(\"&lt;a&gt;innerHtml&lt;/a&gt;&lt;/a&gt;\")                      = \"innerHtml\";\n     * getHrefInnerHtml(\"jack&lt;a&gt;innerHtml&lt;/a&gt;&lt;/a&gt;\")                  = \"innerHtml\";\n     * getHrefInnerHtml(\"&lt;a&gt;innerHtml1&lt;/a&gt;&lt;a&gt;innerHtml2&lt;/a&gt;\")        = \"innerHtml2\";\n     * </pre>\n     * \n     * @param href\n     * @return <ul>\n     *         <li>if href is null, return \"\"</li>\n     *         <li>if not match regx, return source</li>\n     *         <li>return the last string that match regx</li>\n     *         </ul>\n     */\n    public static String getHrefInnerHtml(String href) {\n        if (isEmpty(href)) {\n            return \"\";\n        }\n\n        String hrefReg = \".*<[\\\\s]*a[\\\\s]*.*>(.+?)<[\\\\s]*/a[\\\\s]*>.*\";\n        Pattern hrefPattern = Pattern.compile(hrefReg, Pattern.CASE_INSENSITIVE);\n        Matcher hrefMatcher = hrefPattern.matcher(href);\n        if (hrefMatcher.matches()) {\n            return hrefMatcher.group(1);\n        }\n        return href;\n    }\n\n/**\n     * process special char in html\n     * \n     * <pre>\n     * htmlEscapeCharsToString(null) = null;\n     * htmlEscapeCharsToString(\"\") = \"\";\n     * htmlEscapeCharsToString(\"mp3\") = \"mp3\";\n     * htmlEscapeCharsToString(\"mp3&lt;\") = \"mp3<\";\n     * htmlEscapeCharsToString(\"mp3&gt;\") = \"mp3\\>\";\n     * htmlEscapeCharsToString(\"mp3&amp;mp4\") = \"mp3&mp4\";\n     * htmlEscapeCharsToString(\"mp3&quot;mp4\") = \"mp3\\\"mp4\";\n     * htmlEscapeCharsToString(\"mp3&lt;&gt;&amp;&quot;mp4\") = \"mp3\\<\\>&\\\"mp4\";\n     * </pre>\n     * \n     * @param source\n     * @return\n     */\n    public static String htmlEscapeCharsToString(String source) {\n        return StringUtils.isEmpty(source) ? source : source.replaceAll(\"&lt;\", \"<\").replaceAll(\"&gt;\", \">\")\n                .replaceAll(\"&amp;\", \"&\").replaceAll(\"&quot;\", \"\\\"\");\n    }\n\n    /**\n     * transform half width char to full width char\n     * \n     * <pre>\n     * fullWidthToHalfWidth(null) = null;\n     * fullWidthToHalfWidth(\"\") = \"\";\n     * fullWidthToHalfWidth(new String(new char[] {12288})) = \" \";\n     * fullWidthToHalfWidth(\"！＂＃＄％＆) = \"!\\\"#$%&\";\n     * </pre>\n     * \n     * @param s\n     * @return\n     */\n    public static String fullWidthToHalfWidth(String s) {\n        if (isEmpty(s)) {\n            return s;\n        }\n\n        char[] source = s.toCharArray();\n        for (int i = 0; i < source.length; i++) {\n            if (source[i] == 12288) {\n                source[i] = ' ';\n                // } else if (source[i] == 12290) {\n                // source[i] = '.';\n            } else if (source[i] >= 65281 && source[i] <= 65374) {\n                source[i] = (char)(source[i] - 65248);\n            } else {\n                source[i] = source[i];\n            }\n        }\n        return new String(source);\n    }\n\n    /**\n     * transform full width char to half width char\n     * \n     * <pre>\n     * halfWidthToFullWidth(null) = null;\n     * halfWidthToFullWidth(\"\") = \"\";\n     * halfWidthToFullWidth(\" \") = new String(new char[] {12288});\n     * halfWidthToFullWidth(\"!\\\"#$%&) = \"！＂＃＄％＆\";\n     * </pre>\n     * \n     * @param s\n     * @return\n     */\n    public static String halfWidthToFullWidth(String s) {\n        if (isEmpty(s)) {\n            return s;\n        }\n\n        char[] source = s.toCharArray();\n        for (int i = 0; i < source.length; i++) {\n            if (source[i] == ' ') {\n                source[i] = (char)12288;\n                // } else if (source[i] == '.') {\n                // source[i] = (char)12290;\n            } else if (source[i] >= 33 && source[i] <= 126) {\n                source[i] = (char)(source[i] + 65248);\n            } else {\n                source[i] = source[i];\n            }\n        }\n        return new String(source);\n    }\n\n\n    //判断email格式是否正确\n    public static boolean isEmail(String email) {\n        String str = \"^([a-zA-Z0-9_\\\\-\\\\.]+)@((\\\\[[0-9]{1,3}\\\\.[0-9]{1,3}\\\\.[0-9]{1,3}\\\\.)|(([a-zA-Z0-9\\\\-]+\\\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\\\]?)$\";\n        Pattern p = Pattern.compile(str);\n        Matcher m = p.matcher(email);\n\n        return m.matches();\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_business/cache/BaseCache.java",
    "content": "package com.bzai.gamesdk.common.utils_business.cache;\n\nimport android.app.Application;\nimport android.content.Context;\nimport android.text.TextUtils;\n\n\nimport com.bzai.gamesdk.common.utils_base.frame.walle.WalleChannelReader;\nimport com.bzai.gamesdk.common.utils_base.frame.walle.payload_reader.ChannelInfo;\nimport com.bzai.gamesdk.common.utils_business.config.KeyConfig;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * Created by bzai on 2018/4/9.\n *\n * 全局缓存数据类\n *\n */\n\npublic class BaseCache {\n\n    private static final String TAG = \"BaseCache\";\n\n    private Application mAppContext;\n    public Context getApplication() {\n        return mAppContext;\n    }\n\n    /********************* 同步锁双重检测机制实现单例模式（懒加载）********************/\n\n    private volatile static BaseCache sCache;\n    private BaseCache(Application appContext) {\n        mAppContext = appContext;\n    }\n\n    public static BaseCache getInstance() {\n        if (sCache == null) {\n            throw new RuntimeException(\"get(Context) never called\");\n        }\n        return sCache;\n    }\n\n    public static BaseCache init(Application cxt) {\n        if (sCache == null) {\n            synchronized (BaseCache.class) {\n                if (sCache == null) {\n                    sCache = new BaseCache(cxt);\n                }\n            }\n        }\n        return sCache;\n    }\n\n    /********************* 同步锁双重检测机制实现单例模式（懒加载）********************/\n\n    /**\n     * hashMap是线程不安全的，做全局缓存时，用锁来保证存储值\n     */\n    private ConcurrentHashMap<String, Object> mConfigs = new ConcurrentHashMap<>();\n    private ReentrantLock mLock = new ReentrantLock();\n\n    public void put(String key, Object value){\n        mLock.lock();\n        mConfigs.put(key,value);\n        mLock.unlock();\n    }\n\n    public Object get(String key){\n        mLock.lock();\n        Object object = mConfigs.get(key);\n        mLock.unlock();\n        return object;\n    }\n\n\n\n    /*********************************************  定义常用方法，方便后续其他地方要用到  **********************************************/\n\n    /**\n     * 返回游戏的GameID\n     * @return\n     */\n    public String getGameId() {\n        return (String) get(KeyConfig.GAME_ID);\n    }\n\n    /**\n     * 返回游戏的GameName\n     * @return\n     */\n    public String getGameName() {\n        return (String) get(KeyConfig.GAME_NAME);\n    }\n\n    /**\n     * 返回游戏的GameKey\n     * @return\n     */\n    public String getGameKey() {\n        return (String) get(KeyConfig.GAME_KEY);\n    }\n\n\n    /**\n     * 返回项目SDK类型,默认返回1\n     * @return\n     */\n    public String getSdkType(){\n        return TextUtils.isEmpty((String) get(KeyConfig.SDK_TYPE)) ? \"1\" : (String) get(KeyConfig.SDK_TYPE);\n    }\n\n    /**\n     * 返回项目SDK类型\n     * @return\n     */\n    public String getSdkName(){\n        return (String) get(KeyConfig.SDK_NAME);\n    }\n\n    /**\n     * 返回项目SDK版本\n     * @return\n     */\n    public String getSdkVersion(){\n        return (String)get(KeyConfig.SDK_VERSION);\n    }\n\n    /**\n     * 返回项目SDK分包标识,\n     * 因为分包标识是在出包时通过命名行打进去的,\n     * 默认读取配置的配置.\n     *\n     * 注意：不是以配置文件为准。\n     *\n     * @return\n     */\n    public String getSdkTagId(){\n        ChannelInfo channelInfo = WalleChannelReader.getChannelInfo(getApplication().getApplicationContext());\n        if (channelInfo == null){\n            return \"1\"; //读取默认配置的字段\n        }\n        return channelInfo.getChannel();\n    }\n\n    /**\n     * 返回项目SDK域名地址，方便切换域名测试\n     * @return\n     */\n    public String getSdkUrl(){\n        return (String)get(KeyConfig.SDK_URL);\n    }\n\n    /**\n     * 返回渠道的ID\n     * @return\n     */\n    public String getChannelId() {\n        return (String)get(KeyConfig.CHANNEL_ID);\n    }\n\n    /**\n     * 返回渠道的名称\n     * @return\n     */\n    public String getChannelName(){\n        return (String)get(KeyConfig.CHANNEL_NAME);\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_business/cache/SDKInfoCache.java",
    "content": "package com.bzai.gamesdk.common.utils_business.cache;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc:\n *\n *   初始化配置文件信息\n */\npublic class SDKInfoCache {\n\n    private Context mAppContext;\n    private ConcurrentHashMap<String, String> mFileStrings = new ConcurrentHashMap<String, String>();\n\n    private static String SDK_Json = \"SDKInfo.json\";\n\n    /********************* 同步锁双重检测机制实现单例模式（懒加载）********************/\n\n    private static SDKInfoCache sLoader;\n    public static SDKInfoCache getDefault(Context cxt) {\n        if (sLoader == null) {\n            synchronized (SDKInfoCache.class) {\n                if (sLoader == null) {\n                    sLoader = new SDKInfoCache(cxt.getApplicationContext());\n                }\n            }\n        }\n        return sLoader;\n    }\n\n    private SDKInfoCache(Context appContext) {\n        mAppContext = appContext;\n        setConfig(SDK_Json,parseConfig(SDK_Json));\n    }\n\n    /********************* 同步锁双重检测机制实现单例模式（懒加载）********************/\n\n    private static HashMap<String, String> mConfigs = new HashMap<String, String>();\n\n    public String get(String key) {\n        return mConfigs.get(key);\n    }\n\n    public void setConfig(String filePath, HashMap<String, String> configs) {\n\n        LogUtils.debug_d(filePath + \"=\" + configs.toString());\n        if (configs != null){\n            mConfigs.putAll(configs);\n\n            //同时将数据存储到YZWBaseCache中\n            for (String key: configs.keySet()){\n                BaseCache.getInstance().put(key,get(key));\n            }\n        }\n\n    }\n\n    private HashMap<String, String> parseConfig(String filePath) {\n        HashMap<String, String> mConfigs = new HashMap<String, String>();\n        String configs = readFile(filePath);\n        LogUtils.d(filePath + \" = \" +configs);\n        if (!configs.equals(\"\")) {\n            try {\n                JSONObject jo = new JSONObject(configs);\n                Iterator<?> keys = jo.keys();\n                while (keys.hasNext()) {\n                    String key = keys.next().toString();\n                    mConfigs.put(key, jo.getString(key));\n                }\n            } catch (JSONException e2) {\n                LogUtils.e(e2.toString());\n            }\n        }\n        return mConfigs;\n    }\n\n    /**\n     * 需要同步锁，公有数据缓存 mFileStrings\n     * @param fileName\n     * @return\n     */\n    private synchronized String readFile(String fileName) {\n        if (TextUtils.isEmpty(fileName)) {\n            return \"\";\n        }\n\n        String content = mFileStrings.get(fileName);\n        if (content != null) {\n            return content;\n        }\n\n        InputStream is = null;\n        ByteArrayOutputStream baos = null;\n        try {\n            is = mAppContext.getAssets().open(fileName);\n            byte[] buffer = new byte[1024];\n            int readBytes = is.read(buffer);\n            baos = new ByteArrayOutputStream(1024);\n            while (0 < readBytes) {\n                baos.write(buffer, 0, readBytes);\n                readBytes = is.read(buffer);\n            }\n            String s = baos.toString();\n            mFileStrings.put(fileName, s);\n            return s;\n        } catch (IOException e) {\n            LogUtils.debug_e(e.toString());\n        } finally {\n            if (null != is) {\n                try {\n                    is.close();\n                } catch (IOException e) {\n                }\n            }\n            if (null != baos) {\n                try {\n                    baos.close();\n                } catch (IOException e) {\n                }\n            }\n        }\n\n        mFileStrings.put(fileName, \"\");\n        return \"\";\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_business/cache/SharePreferencesCache.java",
    "content": "package com.bzai.gamesdk.common.utils_business.cache;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\n\nimport com.bzai.gamesdk.common.utils_base.frame.google.gson.Gson;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport static android.content.Context.MODE_PRIVATE;\nimport static android.content.Context.MODE_WORLD_READABLE;\nimport static android.content.Context.MODE_WORLD_WRITEABLE;\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc:\n *\n *  持久化数据缓存类\n *\n */\npublic class SharePreferencesCache {\n\n    private static SharedPreferences mSharedPreferences;\n    private static Gson mGson;\n    private static int INVALID_VALUE = -1;\n\n    private Context mContext;\n    private String mName = \"SDK.SpCache\";\n    private int mMode;\n\n    /**\n     * Initial the preferences manager.\n     *\n     * @param context The context of the application.\n     */\n    public SharePreferencesCache(Context context) {\n        mContext = context;\n        mGson = new Gson();\n        mMode = INVALID_VALUE;\n    }\n\n    /**\n     * Set the mode of the preferences.\n     *\n     * @param mode The mode of the preferences.\n     */\n    private SharePreferencesCache setMode(int mode) {\n        mMode = mode;\n        return this;\n    }\n\n    /**\n     * Initial the instance of the preferences manager.\n     */\n    public void init() {\n        if (mContext == null) {\n            return;\n        }\n\n        if (mName.isEmpty()) {\n            mName = mContext.getPackageName();\n        }\n\n        if (mMode == INVALID_VALUE || (mMode != MODE_PRIVATE && mMode != MODE_WORLD_READABLE\n                && mMode != MODE_WORLD_WRITEABLE)) {\n            mMode = MODE_PRIVATE;\n        }\n\n        mSharedPreferences = mContext.getSharedPreferences(mName, mMode);\n    }\n\n    /**\n     * Put a String value in the preferences editor.\n     *\n     * @param key   The name of the preference to modify.\n     * @param value The new value for the preference.\n     */\n    public static void putString(String key, String value) {\n        if (mSharedPreferences == null) {\n            return;\n        }\n\n        SharedPreferences.Editor editor = mSharedPreferences.edit();\n        editor.putString(key, value);\n        editor.apply();\n    }\n\n    /**\n     * Retrieval a String value from the preferences.\n     *\n     * @param key      The name of the preference to retrieve.\n     * @param defValue Value to return if this preference does not exist.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static String getString(String key, String defValue) {\n        if (mSharedPreferences == null) {\n            return defValue;\n        }\n        return mSharedPreferences.getString(key, defValue);\n    }\n\n    /**\n     * Retrieval a String value from the preferences.\n     *\n     * @param key The name of the preference to retrieve.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static String getString(String key) {\n        return getString(key, \"\");\n    }\n\n    /**\n     * Put a set of String values in the preferences editor.\n     *\n     * @param key    The name of the preference to modify.\n     * @param values The set of new values for the preference.\n     */\n    public static void putStringSet(String key, Set<String> values) {\n        if (mSharedPreferences == null) {\n            return;\n        }\n\n        SharedPreferences.Editor editor = mSharedPreferences.edit();\n        editor.putStringSet(key, values);\n        editor.apply();\n    }\n\n    /**\n     * Retrieval a set of String values from the preferences.\n     *\n     * @param key       The name of the preference to retrieve.\n     * @param defValues Values to return if this preference does not exist.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static Set<String> getStringSet(String key, Set<String> defValues) {\n        if (mSharedPreferences == null) {\n            return defValues;\n        }\n        return mSharedPreferences.getStringSet(key, defValues);\n    }\n\n    /**\n     * Retrieval a set of String values from the preferences.\n     *\n     * @param key The name of the preference to retrieve.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static Set<String> getStringSet(String key) {\n        return getStringSet(key, new HashSet<String>());\n    }\n\n    /**\n     * Put an int value in the preferences editor.\n     *\n     * @param key   The name of the preference to modify.\n     * @param value The new value for the preference.\n     */\n    public static void putInt(String key, int value) {\n        if (mSharedPreferences == null) {\n            return;\n        }\n\n        SharedPreferences.Editor editor = mSharedPreferences.edit();\n        editor.putInt(key, value);\n        editor.apply();\n    }\n\n\n    /**\n     * Retrieval an int value from the preferences.\n     *\n     * @param key      The name of the preference to retrieve.\n     * @param defValue Value to return if this preference does not exist.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static int getInt(String key, int defValue) {\n        if (mSharedPreferences == null) {\n            return defValue;\n        }\n        return mSharedPreferences.getInt(key, defValue);\n    }\n\n    /**\n     * Retrieval an int value from the preferences.\n     *\n     * @param key The name of the preference to retrieve.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static int getInt(String key) {\n        return getInt(key, 0);\n    }\n\n    /**\n     * Put a float value in the preferences editor.\n     *\n     * @param key   The name of the preference to modify.\n     * @param value The new value for the preference.\n     */\n    public static void putFloat(String key, float value) {\n        if (mSharedPreferences == null) {\n            return;\n        }\n\n        SharedPreferences.Editor editor = mSharedPreferences.edit();\n        editor.putFloat(key, value);\n        editor.apply();\n    }\n\n    /**\n     * Retrieval a float value from the preferences.\n     *\n     * @param key      The name of the preference to retrieve.\n     * @param defValue Value to return if this preference does not exist.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static float getFloat(String key, float defValue) {\n        if (mSharedPreferences == null) {\n            return defValue;\n        }\n        return mSharedPreferences.getFloat(key, defValue);\n    }\n\n    /**\n     * Retrieval a float value from the preferences.\n     *\n     * @param key The name of the preference to retrieve.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static float getFloat(String key) {\n        return getFloat(key, 0);\n    }\n\n    /**\n     * Put a long value in the preferences editor.\n     *\n     * @param key   The name of the preference to modify.\n     * @param value The new value for the preference.\n     */\n    public static void putLong(String key, long value) {\n        if (mSharedPreferences == null) {\n            return;\n        }\n\n        SharedPreferences.Editor editor = mSharedPreferences.edit();\n        editor.putLong(key, value);\n        editor.apply();\n    }\n\n    /**\n     * Retrieval a long value from the preferences.\n     *\n     * @param key      The name of the preference to retrieve.\n     * @param defValue Value to return if this preference does not exist.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static long getLong(String key, long defValue) {\n        if (mSharedPreferences == null) {\n            return defValue;\n        }\n        return mSharedPreferences.getLong(key, defValue);\n    }\n\n    /**\n     * Retrieval a long value from the preferences.\n     *\n     * @param key The name of the preference to retrieve.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static long getLong(String key) {\n        return getLong(key, 0);\n    }\n\n    /**\n     * Put a boolean value in the preferences editor.\n     *\n     * @param key   The name of the preference to modify.\n     * @param value The new value for the preference.\n     */\n    public static void putBoolean(String key, boolean value) {\n        if (mSharedPreferences == null) {\n            return;\n        }\n\n        SharedPreferences.Editor editor = mSharedPreferences.edit();\n        editor.putBoolean(key, value);\n        editor.apply();\n    }\n\n    /**\n     * Retrieval a boolean value from the preferences.\n     *\n     * @param key      The name of the preference to retrieve.\n     * @param defValue Value to return if this preference does not exist.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static boolean getBoolean(String key, boolean defValue) {\n        if (mSharedPreferences == null) {\n            return defValue;\n        }\n        return mSharedPreferences.getBoolean(key, defValue);\n    }\n\n    /**\n     * Retrieval a boolean value from the preferences.\n     *\n     * @param key The name of the preference to retrieve.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static boolean getBoolean(String key) {\n        return getBoolean(key, false);\n    }\n\n    /**\n     * Put a object in the preferences editor.\n     *\n     * @param key   The name of the preference to modify.\n     * @param value The new value for the preference.\n     */\n    public static void putObject(String key, Object value) {\n        if (mGson == null || value == null) {\n            return;\n        }\n\n        putString(key, mGson.toJson(value));\n    }\n\n    /**\n     * Retrieval a object from the preferences.\n     *\n     * @param key  The name of the preference to retrieve.\n     * @param type The class of the preference to retrieve.\n     * @return Returns the preference values if they exist, or defValues.\n     */\n    public static <T> T getObject(String key, Class<T> type) {\n        if (mSharedPreferences == null || mGson == null) {\n            return null;\n        }\n        return mGson.fromJson(getString(key), type);\n    }\n\n    /**\n     * Remove a preference from the preferences editor.\n     *\n     * @param key The name of the preference to remove.\n     */\n    public static void remove(String key) {\n        if (mSharedPreferences == null) {\n            return;\n        }\n        mSharedPreferences.edit().remove(key).apply();\n    }\n\n    /**\n     * Remove all values from the preferences editor.\n     */\n    public static void clear() {\n        if (mSharedPreferences == null) {\n            return;\n        }\n        mSharedPreferences.edit().clear().apply();\n    }\n\n    /**\n     * Registers a callback to be invoked when a change happens to a preference.\n     *\n     * @param listener The callback that will run.\n     */\n    private static void registerOnChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) {\n        if (mSharedPreferences == null) {\n            return;\n        }\n        mSharedPreferences.registerOnSharedPreferenceChangeListener(listener);\n    }\n\n    /**\n     * Unregisters a previous callback.\n     *\n     * @param listener The callback that should be unregistered.\n     */\n    private static void unregisterOnChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener) {\n        if (mSharedPreferences == null) {\n            return;\n        }\n        mSharedPreferences.unregisterOnSharedPreferenceChangeListener(listener);\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_business/config/KeyConfig.java",
    "content": "package com.bzai.gamesdk.common.utils_business.config;\n\n/**\n * Created by bzai on 2018/6/11.\n * <p>\n * Desc:\n *\n *  管理KEY值配置\n *\n */\n\npublic class KeyConfig {\n\n    /*************  配置游戏字段  **********/\n    public static final String GAME_ID = \"game_id\"; //游戏的gameid\n    public static final String GAME_KEY = \"game_key\";//游戏的gamekey\n    public static final String GAME_NAME = \"game_name\"; //游戏名称\n\n\n\n    /*************  配置用户字段  **********/\n    public static final String PLAYER_ID = \"player_id\";\n    public static final String PLAYER_NAME = \"player_name\";\n    public static final String PLAYER_TOKEN = \"player_token\";\n\n\n\n    /*************  接口状态配置字段  **********/\n    public static final String IS_INIT = \"is_init\";\n    public static final String IS_LOGIN = \"is_login\";\n\n\n\n    /*************  配置文件配置字段  **********/\n    public static String SDK_TYPE = \"sdk_type\";\n    public static String SDK_NAME = \"sdk_name\";\n    public static String SDK_VERSION = \"sdk_version\";\n    public static String SDK_URL = \"sdk_url\";\n    public static String CHANNEL_ID = \"channel_id\";\n    public static String CHANNEL_NAME = \"channel_name\";\n\n\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_business/config/UrlConfig.java",
    "content": "package com.bzai.gamesdk.common.utils_business.config;\n\nimport android.text.TextUtils;\n\nimport com.bzai.gamesdk.common.utils_base.utils.LogUtils;\nimport com.bzai.gamesdk.common.utils_business.cache.BaseCache;\n\n\n/**\n * Created by bzai on 2018/4/14.\n * <p>\n * Desc:\n *\n * 域名配置\n *\n */\n\npublic class UrlConfig {\n\n    private static final String TAG = \"UrlConfig\";\n\n    private static String Project_SDKUrl; //url\n\n    //项目的基础ip域名地址\n    private static String Project_BaseApi = \"https://www.baidu.com/\";\n\n\n    public static String getSdkUrl(){\n        return Project_SDKUrl;\n    }\n\n    public static void initUrl(){\n\n        //通过配置读取域名\n        String SDK_Base_Url = BaseCache.getInstance().getSdkUrl();\n\n        if (!TextUtils.isEmpty(SDK_Base_Url)){//通过配置文件来修改域名\n            Project_BaseApi = SDK_Base_Url;\n        }\n\n        LogUtils.debug_d(TAG,Project_SDKUrl);\n    }\n\n    /**\n     *  预设设置修改当前网络的请求域名接口\n     *  思考特殊的场景：\n     *\n     */\n    public static String getReSetUrl(String sdk_type, String channelId){\n\n        String tempUrl = \"\";\n        return tempUrl; //返回临时的域名\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_ui/BitmapUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_ui;\n\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Matrix;\nimport android.util.Base64;\n\nimport com.bzai.gamesdk.common.utils_base.cache.ApplicationCache;\n\nimport java.io.BufferedOutputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.text.DecimalFormat;\n\n/**\n * Created by bzai on 2018/5/26.\n * <p>\n * Desc:\n *\n *  处理图片Bitmap\n */\n\npublic class BitmapUtils {\n\n    /**\n     * 获取网络图片\n     */\n    public static Bitmap getImageBitmap(String imageUrl) {\n        if (null == imageUrl) {\n            return null;\n        }\n        Bitmap bitmap = null;\n        try {\n            URL url = new URL(imageUrl);\n            HttpURLConnection conn = (HttpURLConnection) url.openConnection();\n            conn.setDoInput(true);\n            conn.setReadTimeout(5000);\n            conn.setRequestMethod(\"GET\");\n            if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){\n                InputStream inputStream = conn.getInputStream();\n                bitmap = BitmapFactory.decodeStream(inputStream);\n                inputStream.close();\n            }\n            conn.disconnect();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return bitmap;\n    }\n\n    /**\n     * 保存图片到私有内存\n     * @param bm\n     * @param fileName\n     * @return\n     */\n    public static String savePicture(Bitmap bm, String fileName){\n\n        try {\n            File file = ApplicationCache.getInstance().getApplicationContext().getExternalCacheDir(); //SDCard/Android/data/应用包名/cache/\n            File pictureFile = new File(file.getPath(), fileName);\n            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(pictureFile));\n\n            //处理格式：\n            if (fileName.endsWith(\".png\") ) {\n                bm.compress(Bitmap.CompressFormat.PNG, 100, bos);\n            }else if (fileName.endsWith(\".jpg\")){\n                bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);\n            }\n\n            bos.flush();\n            bos.close();\n            return pictureFile.getAbsolutePath();\n\n        } catch (Exception e) {\n        }\n        return null;\n    }\n\n    /**\n     * 读取私有目录下的指定文件\n     * @return\n     */\n    public static Bitmap getPicture(String fileName){\n\n        String path = ApplicationCache.getInstance().getApplicationContext().getExternalCacheDir().getPath();\n        File file = new File(path,fileName);\n\n        Bitmap bitmap = null;\n        InputStream is = null;\n        try {\n\n            is = new FileInputStream(file);\n            if (is != null){\n                bitmap = BitmapFactory.decodeStream(is);\n                is.close();\n            }\n        }catch (Exception e){\n            e.printStackTrace();\n        }finally {\n            if (is != null) {\n                try {\n                    is.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n\n        return bitmap;\n    }\n\n    /**\n     * 图片的缩放方法\n     *\n     * @param bitmap  ：源图片资源\n     * @param maxSize ：图片允许最大空间  单位:KB\n     * @return\n     */\n    public static Bitmap getZoomImage(Bitmap bitmap, double maxSize) {\n        if (null == bitmap) {\n            return null;\n        }\n        if (bitmap.isRecycled()) {\n            return null;\n        }\n\n        // 单位：从 Byte 换算成 KB\n        double currentSize = bitmapToByteArray(bitmap, false).length / 1024;\n        // 判断bitmap占用空间是否大于允许最大空间,如果大于则压缩,小于则不压缩\n        while (currentSize > maxSize) {\n            // 计算bitmap的大小是maxSize的多少倍\n            double multiple = currentSize / maxSize;\n            // 开始压缩：将宽带和高度压缩掉对应的平方根倍\n            // 1.保持新的宽度和高度，与bitmap原来的宽高比率一致\n            // 2.压缩后达到了最大大小对应的新bitmap，显示效果最好\n            bitmap = getZoomImage(bitmap, bitmap.getWidth() / Math.sqrt(multiple), bitmap.getHeight() / Math.sqrt(multiple));\n            currentSize = bitmapToByteArray(bitmap, false).length / 1024;\n        }\n        return bitmap;\n    }\n\n    /**\n     * 图片的缩放方法\n     *\n     * @param orgBitmap ：源图片资源\n     * @param newWidth  ：缩放后宽度\n     * @param newHeight ：缩放后高度\n     * @return\n     */\n    public static Bitmap getZoomImage(Bitmap orgBitmap, double newWidth, double newHeight) {\n        if (null == orgBitmap) {\n            return null;\n        }\n        if (orgBitmap.isRecycled()) {\n            return null;\n        }\n        if (newWidth <= 0 || newHeight <= 0) {\n            return null;\n        }\n\n        // 获取图片的宽和高\n        float width = orgBitmap.getWidth();\n        float height = orgBitmap.getHeight();\n        // 创建操作图片的matrix对象\n        Matrix matrix = new Matrix();\n        // 计算宽高缩放率\n        float scaleWidth = ((float) newWidth) / width;\n        float scaleHeight = ((float) newHeight) / height;\n        // 缩放图片动作\n        matrix.postScale(scaleWidth, scaleHeight);\n        Bitmap bitmap = Bitmap.createBitmap(orgBitmap, 0, 0, (int) width, (int) height, matrix, true);\n        return bitmap;\n    }\n\n    /**\n     * bitmap转换成byte数组\n     *\n     * @param bitmap\n     * @param needRecycle\n     * @return\n     */\n    public static byte[] bitmapToByteArray(Bitmap bitmap, boolean needRecycle) {\n        if (null == bitmap) {\n            return null;\n        }\n        if (bitmap.isRecycled()) {\n            return null;\n        }\n\n        ByteArrayOutputStream output = new ByteArrayOutputStream();\n        bitmap.compress(Bitmap.CompressFormat.PNG, 100, output);\n        if (needRecycle) {\n            bitmap.recycle();\n        }\n\n        byte[] result = output.toByteArray();\n        try {\n            output.close();\n        } catch (Exception e) {\n            e.toString();\n        }\n        return result;\n    }\n\n    /**\n     * bitmap转化为string\n     * @param bitmap\n     * @return\n     */\n    public static String bitmapToString(Bitmap bitmap){\n\n        if (null == bitmap) {\n            return null;\n        }\n\n        ByteArrayOutputStream output = new ByteArrayOutputStream();\n        bitmap.compress(Bitmap.CompressFormat.PNG, 100, output);\n\n        byte[] result = output.toByteArray();\n        String temp = Base64.encodeToString(result, Base64.DEFAULT);\n        try {\n            output.close();\n        } catch (Exception e) {\n            e.toString();\n        }\n\n        return temp;\n\n    }\n\n\n    /**\n     * string转成bitmap\n     *\n     * @param st\n     */\n    public static Bitmap stringToBitmap(String st)\n    {\n\n        Bitmap bitmap = null;\n        try\n        {\n            byte[] bitmapArray;\n            bitmapArray = Base64.decode(st, Base64.DEFAULT);\n            bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0,\n                            bitmapArray.length);\n            return bitmap;\n        }\n        catch (Exception e)\n        {\n            return null;\n        }\n    }\n\n    /**\n     * 图片的大小\n     * @param size\n     * @return\n     */\n    public String getReadableFileSize(long size) {\n        if (size <= 0) {\n            return \"0\";\n        }\n        final String[] units = new String[]{\"B\", \"KB\", \"MB\", \"GB\", \"TB\"};\n        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));\n        return new DecimalFormat(\"#,##0.#\").format(size / Math.pow(1024, digitGroups)) + \" \" + units[digitGroups];\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_ui/LoadingUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_ui;\n\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.os.Handler;\nimport android.os.Looper;\n\n/**\n * 加载框\n */\npublic class LoadingUtils {\n\n    private ProgressDialog mProgress;\n    private Handler sMainHandler = new Handler(Looper.getMainLooper());\n    \n    public LoadingUtils(Context context){\n        mProgress = new ProgressDialog(context);\n        mProgress.setMessage(\"Loading...\");\n    }\n    \n    public void setMessage(String message){\n        mProgress.setMessage(message);\n    }\n    \n    public void show(){\n        try {\n            if(mProgress != null){\n                sMainHandler.post(new Runnable() {\n                    \n                    @Override\n                    public void run() {\n                        mProgress.show();\n                    }\n                });\n            }\n        } catch (Exception e) {\n        }\n    }\n    \n    public void dismiss(){\n        if(mProgress != null && mProgress.isShowing()){\n            sMainHandler.post(new Runnable() {\n                \n                @Override\n                public void run() {\n                    try {\n                        mProgress.dismiss();\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                    }\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_ui/ResourseIdUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_ui;\n\nimport android.content.Context;\n\nimport com.bzai.gamesdk.common.utils_base.cache.ApplicationCache;\n\n\n/**\n * Created by bzai on 2018/4/18.\n * <p>\n * Desc: 加载系统目录下资源工具类\n *\n */\npublic class ResourseIdUtils {\n\n    public static int getId(String name) {\n        return getResourceIdByName(\"id\", name);\n    }\n\n    public static int getStyleByName(String name) {\n        return getResourceIdByName(\"style\", name);\n    }\n\n    public static int getStringId(String name) {\n        return getResourceIdByName(\"string\", name);\n    }\n\n    public static int getColorId(String name) {\n        return getResourceIdByName(\"color\", name);\n    }\n\n    public static int getStringArrayId(String name) {\n        return getResourceIdByName(\"array\", name);\n    }\n\n    public static int getDimenId(String dimenName) {\n        return getResourceIdByName(\"dimen\", dimenName);\n    }\n    \n    public static int getDrawableId(String name) {\n        return getResourceIdByName(\"drawable\", name);\n    }\n\n    public static int getLayoutId(String name) {\n        return getResourceIdByName(\"layout\", name);\n    }\n\n    public static int getAnimId(String name) {\n        return getResourceIdByName(\"anim\", name);\n    }\n\n    public static int getResourceIdByName(String className, String name) {\n        int id = 0;\n        try {\n            Context context = ApplicationCache.getInstance().getApplicationContext();\n            String packageName = context.getPackageName();\n            id = context.getResources().getIdentifier(name, className, packageName);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return id;\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_ui/ToastUtils.java",
    "content": "package com.bzai.gamesdk.common.utils_ui;\n\nimport android.content.Context;\nimport android.widget.Toast;\n\n/**\n * Created by bzai on 2018/5/24.\n * <p>\n * Desc:\n *\n *  Toast 公共类\n */\n\npublic class ToastUtils {\n\n    private static Toast toast;\n\n    public static void showToast(Context context,\n                                 String content) {\n\n        if (content == null){\n            return;\n        }\n        if (toast == null) {\n            toast = Toast.makeText(context, content, Toast.LENGTH_SHORT);\n        } else {\n            toast.setText(content);\n        }\n        toast.show();\n    }\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/main/java/com/bzai/gamesdk/common/utils_ui/activity/SplashActivity.java",
    "content": "package com.bzai.gamesdk.common.utils_ui.activity;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.res.AssetManager;\nimport android.graphics.BitmapFactory;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.Window;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Timer;\nimport java.util.TimerTask;\n\n/**\n * @author bzai\n * @data 2019/1/28\n * <p>\n * Desc: 闪屏\n */\npublic class SplashActivity extends Activity {\n\n    private ImageView mView ;\n    private AssetManager mAssets;\n    private int mImageIndex = 0;\n    private String[] mImages;\n\n    private void hideVirtualButtons() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            getWindow().getDecorView().setSystemUiVisibility(\n                    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION\n                            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);\n        }\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        requestWindowFeature(Window.FEATURE_NO_TITLE);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);\n\n        mView = new ImageView(this);\n        mView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));\n\n        mAssets = getAssets();\n\n        try {\n            // 可以数组特性，来区分闪屏前后顺序\n            mImages = mAssets.list(\"splash\");\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n\n        LinearLayout layout = new LinearLayout(this);\n        layout.setGravity(Gravity.CENTER);\n\n        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(\n                FrameLayout.LayoutParams.MATCH_PARENT,\n                FrameLayout.LayoutParams.MATCH_PARENT);\n        addContentView(layout, params);\n        layout.addView(mView);\n\n\n\n        final Timer timer = new Timer();\n        TimerTask timerTask = new TimerTask() {\n            @Override\n            public void run() {\n\n                runOnUiThread(new Runnable() {\n\n                    @Override\n                    public void run() {\n\n                        if(mImageIndex < mImages.length){\n                            String newFileName = \"splash/\"+mImages[mImageIndex++];\n                            InputStream newSplashFile;\n                            try {\n                                newSplashFile   =  mAssets.open(newFileName);\n                                mView.setImageBitmap(BitmapFactory.decodeStream(newSplashFile));\n                                mView.setScaleType(ImageView.ScaleType.FIT_XY);\n\n                            } catch (IOException e) {\n                                e.printStackTrace();\n                            }\n\n                        }else{\n\n                            timer.cancel();\n                            //找到主入口\n                            Intent intent = new Intent(\"Bzai.MAIN\");\n                            intent.setPackage(SplashActivity.this.getPackageName());\n                            startActivity(intent);\n                            SplashActivity.this.finish();\n                        }\n                    }\n                });\n            }\n        };\n\n        timer.schedule(timerTask, 0 , 1500);\n        hideVirtualButtons();\n\n    }\n\n}\n"
  },
  {
    "path": "GameSDK_Utils/src/test/java/com/bzai/gamesdk/utils/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdk.utils;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "README.md",
    "content": "# GameSDKFrameDemo\n手游SDK框架Demo，不具备实际项目用途，仅做框架Demo展示\n\n###架构图\n![image text](https://github.com/Bzaigege/GameSDKFrameDemo/blob/master/git/SDK%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1.png)\n\n相关的资料说明可参考：\n\n* [手游SDK — 第一篇（序言）](https://www.jianshu.com/p/44e844ad7308)\n* [手游SDK — 第二篇（SDK架构设计篇）](https://www.jianshu.com/p/0d27ee9f7f3a)\n* [手游SDK — 第三篇（SDK架构设计代码实现篇（上）- 基础库）](https://www.jianshu.com/p/152fd3af1193)\n* [手游SDK — 第四篇（SDK架构设计代码实现篇（下）- 项目需求开发）](https://www.jianshu.com/p/4d513b93dc3d)\n\n拓展资料：\n\n如果游戏的主要业务是聚合SDK(联运SDK或融合SDK)的话，主要是面向对接渠道SDK的，会涉及到游戏打渠道的，可以参考下相关博客说明：\n\n* [手游SDK — 第五篇（游戏打包篇（上）- 打包系统设计）](https://www.jianshu.com/p/e86e106304d3)\n* [手游SDK — 第六篇（游戏打包篇（中）- 自动化打包）](https://www.jianshu.com/p/e75dceb6c7f2)\n* [手游SDK — 第七篇（游戏打包篇（下）- 自动化打包踩坑记录）](https://www.jianshu.com/p/16f852b3aabb)\n\n及打包开源项目：[PackageApkTool](https://github.com/Bzaigege/PackageApkTool)\n\n相关游戏SDK的系统解决方案，可以关注本人博客地址：\nhttps://www.jianshu.com/u/03e21de603b7\n\n如果能帮助到你，star支持下\n\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"27.0.3\"\n    defaultConfig {\n        applicationId \"com.bzai.gamesdkframe\"\n        minSdkVersion 14\n        targetSdkVersion 26\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile project(':GameSDK_API')\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "app/src/androidTest/java/com/bzai/gamesdkframe/ExampleInstrumentedTest.java",
    "content": "package com.bzai.gamesdkframe;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.bzai.gamesdkframe\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.bzai.gamesdkframe\">\n\n    <application\n        android:name=\".GameApplication\"\n        android:icon=\"@drawable/ic_launcher\"\n        android:theme=\"@android:style/Theme.Light\"\n        android:label=\"@string/app_name\">\n        <activity android:name=\".GameSDKMain\"\n            android:configChanges=\"fontScale|orientation|keyboardHidden|locale|navigation|screenSize|uiMode\"\n            android:screenOrientation=\"sensorLandscape\">\n            <intent-filter>\n                <action android:name=\"Bzai.MAIN\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n\n        <activity android:name=\"com.bzai.gamesdk.common.utils_ui.activity.SplashActivity\"\n            android:screenOrientation=\"sensorLandscape\"\n            android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\"\n            android:configChanges=\"orientation|screenSize|keyboardHidden\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n\n        </activity>\n\n    </application>\n\n\n\n\n</manifest>"
  },
  {
    "path": "app/src/main/java/com/bzai/gamesdkframe/GameApplication.java",
    "content": "package com.bzai.gamesdkframe;\n\nimport android.content.Context;\n\nimport com.bzai.gamesdk.SDKApplication;\n\n\n/**\n * Created by bzai on 2018/4/10.\n * <p>\n * Desc: 游戏的Application 直接继承SDK的application\n */\n\npublic class GameApplication extends SDKApplication {\n\n    @Override\n    protected void attachBaseContext(Context base) {\n        super.attachBaseContext(base);\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/bzai/gamesdkframe/GameSDKMain.java",
    "content": "package com.bzai.gamesdkframe;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.widget.EditText;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.bzai.gamesdk.GameInfoSetting;\nimport com.bzai.gamesdk.api.SDKAPI;\nimport com.bzai.gamesdk.bean.params.PayParams;\nimport com.bzai.gamesdk.listener.AccountCallBackLister;\nimport com.bzai.gamesdk.listener.ExitCallBackLister;\nimport com.bzai.gamesdk.listener.InitCallBackLister;\nimport com.bzai.gamesdk.listener.PurchaseCallBackListener;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.regex.Pattern;\n\npublic class GameSDKMain extends Activity implements View.OnClickListener{\n\n    private String TAG = getClass().getName();\n    private EditText etPay,etReport;\n    private TextView tvLog;\n    private int pri = 0;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        initView();\n        init();\n    }\n\n\n    private void initView(){\n\n        findViewById(R.id.btn_login).setOnClickListener(this);\n        findViewById(R.id.btn_switchAccount).setOnClickListener(this);\n        findViewById(R.id.btn_logout).setOnClickListener(this);\n        findViewById(R.id.btn_pay).setOnClickListener(this);\n        findViewById(R.id.btn_exit).setOnClickListener(this);\n\n        etPay = (EditText) findViewById(R.id.et_inputPrice);\n        tvLog = (TextView) findViewById(R.id.tvLog);\n    }\n\n\n    @Override\n    public void onClick(View view) {\n        int id = view.getId();\n        switch (id) {\n            case R.id.btn_login:\n                login();\n                break;\n            case R.id.btn_switchAccount:\n                switchAccount();\n                break;\n            case R.id.btn_logout:\n                logout();\n                break;\n            case R.id.btn_pay:\n                purchase();\n                break;\n\n            case R.id.btn_exit:\n                exitGame();\n                break;\n            default:\n                break;\n        }\n    }\n\n\n    private AccountCallBackLister accountCallBackLister = new AccountCallBackLister() {\n\n        @Override\n        public void onAccountEventCallBack(String jsonStr) {\n            tvLog.setText(jsonStr);\n            showToast(jsonStr);\n\n            //CP解析数据格式\n            try {\n                JSONObject jsonObject = new JSONObject(jsonStr);\n                int code = jsonObject.getInt(\"eventType\");\n\n                if (code == AccountCallBackLister.LOGIN_SUCCESS ||\n                        code == AccountCallBackLister.SWITCH_ACCOUNT_SUCCESS){\n\n                }\n\n            } catch (JSONException e) {\n                e.printStackTrace();\n            }\n        }\n    };\n\n\n    private void init() {\n\n        //用于配置游戏的 gameid  和 gamekey\n        String gameid = \"1\";\n        String gamekey = \"222\";\n\n        GameInfoSetting gameInfoSetting = new GameInfoSetting(gameid,gamekey);\n        SDKAPI.getInstance().init(this, gameInfoSetting,accountCallBackLister, new InitCallBackLister() {\n\n            @Override\n            public void onSuccess() {\n                tvLog.setText(\"初始化状态：初始化成功\");\n                showToast(\"初始化状态：初始化成功\");\n            }\n\n            @Override\n            public void onFailure(int code, String msg) {\n                String message = \"初始化状态\"\n                        +\"\\n错误码:\\n\" + code\n                        +\"\\n错误信息:\\n\" + msg;\n                tvLog.setText(message);\n                showToast(message);\n            }\n        });\n    }\n\n\n    /**\n     * 账号登陆\n     */\n    private void login() {\n        SDKAPI.getInstance().login(this);\n    }\n\n    /**\n     * 切换账号\n     */\n    private void switchAccount(){\n        SDKAPI.getInstance().switchAccount(this);\n    }\n\n    /**\n     * 账号登出\n     */\n    private void logout() {\n        SDKAPI.getInstance().logout(this);\n    }\n\n    /**\n     * 购买\n     */\n    private void purchase() {\n\n        String pri_str = etPay.getText().toString();\n        if (!isDecimal(pri_str) && !isInteger(pri_str)) {\n            showToast(\"Please enter Correct values.\");\n            return;\n        }\n\n        try {\n            pri = Integer.valueOf(pri_str);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        /**\n         *  productId\t\t\t商品ID\n         *  productName\t\t\t商品名称\n         *  productDesc\t\t\t商品描述\n         *\n         *  money\t\t\t\t商品单价 (以分为单位)\n         *\n         *  roleID              当前游戏内角色ID\n         *  roleName            当前游戏内角色名称\n         *  roleLevel           玩家等级\n         *  serverID            当前玩家所在的服务器ID\n         *  serverName          当前玩家所在的服务器名称\n         *\n         *  notifyUrl           支付回调地址\n         *  extraInfo\t\t\t透传给 cp服务器的字段\n         *  gorder              CP订单号\n         */\n\n        //商品信息\n        PayParams payParams = new PayParams();\n        payParams.setProductName(\"金币\");\n        payParams.setProductDesc(\"一金币等于十银币\");\n        payParams.setProductId(\"9000\"); //SDK的商品ID\n\n        //金额信息\n        payParams.setMoney(pri);\n\n        //玩家信息\n        payParams.setRoleID(\"123456\");\n        payParams.setRoleName(\"小明\");\n        payParams.setRoleLevel(\"15\");\n        payParams.setServerID(\"11\");\n        payParams.setServerName(\"服务十一区\");\n\n        //支付配置信息\n        payParams.setNotifyUrl(\"www.baidu.com\");\n        payParams.setExtension(\"extra\");\n        payParams.setGorder(\"DD123456\");\n\n        SDKAPI.getInstance().pay(this, payParams,new PurchaseCallBackListener() {\n\n            //创建SDK订单成功就返回，方便CP查询该笔订单状态\n            @Override\n            public void onOrderId(String orderId) {\n                showToast(orderId);\n            }\n\n            @Override\n            public void onSuccess() {\n                String message = \"支付成功\";\n                tvLog.setText(message);\n                showToast(message);\n            }\n\n            @Override\n            public void onFailure(int code, String msg) {\n\n                String message = \"支付失败\\n:\\n错误:\\n\" + code;\n                tvLog.setText(message);\n                showToast(message);\n\n            }\n\n            @Override\n            public void onCancel() {\n                String message = \"支付取消\\n:\\n错误:\\n\" ;\n                tvLog.setText(message);\n                showToast(message);\n            }\n\n            //支付完成，没有正确支付回调时，会返回该结果\n            @Override\n            public void onComplete() {\n                String message = \"支付完成\\n\" ;\n                tvLog.setText(message);\n                showToast(message);\n            }\n\n        });\n    }\n\n\n\n    //--------------------------------------------------退出接口---------------------------------------------\n\n    private void exitGame(){\n\n        SDKAPI.getInstance().exit(GameSDKMain.this,new ExitCallBackLister(){\n\n            //存在退出框,并且点击退出成功\n            @Override\n            public void onExitDialogSuccess() {\n                Log.d(TAG,\"退出成功\");\n                SDKAPI.getInstance().onDestroy(GameSDKMain.this);\n                System.exit(0);\n            }\n\n            //存在退出框,并且点击取消退出\n            @Override\n            public void onExitDialogCancel() {\n                Log.d(TAG,\"退出取消\");\n            }\n\n            //不存在退出框，需要游戏自己实现退出框,然后调用SDK释放资源接口\n            @Override\n            public void onNotExitDialog() {\n\n                AlertDialog.Builder builder = new AlertDialog.Builder(GameSDKMain.this);\n                builder.setTitle(\"退出游戏\");\n                builder.setPositiveButton(\"退出\", new DialogInterface.OnClickListener() {\n\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n\n                        SDKAPI.getInstance().onDestroy(GameSDKMain.this);\n                        System.exit(0);\n                    }\n                });\n                builder.show();\n\n            }\n        });\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        switch (keyCode) {\n            case KeyEvent.KEYCODE_BACK:\n                exitGame();\n                break;\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public void onBackPressed() {\n        super.onBackPressed();\n        exitGame();\n    }\n\n    private void showToast(String msg) {\n        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();\n    }\n\n    // 浮点型判断 (Floating-point judgment)\n    public static boolean isDecimal(String str) {\n        if (str == null || \"\".equals(str))\n            return false;\n        java.util.regex.Pattern pattern = Pattern.compile(\"[0-9]*(\\\\.?)[0-9]*\");\n        return pattern.matcher(str).matches();\n    }\n\n    // 整型判断 (Integer to determine)\n    public static boolean isInteger(String str) {\n        if (str == null)\n            return false;\n        Pattern pattern = Pattern.compile(\"[0-9]+\");\n        return pattern.matcher(str).matches();\n    }\n\n    //--------------------------------------------------生命周期接口---------------------------------------------\n\n    @Override\n    protected void onStart() {\n        super.onStart();\n        SDKAPI.getInstance().onStart(GameSDKMain.this);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        SDKAPI.getInstance().onResume(GameSDKMain.this);\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        SDKAPI.getInstance().onPause(GameSDKMain.this);\n    }\n\n    @Override\n    protected void onStop() {\n        super.onStop();\n        SDKAPI.getInstance().onStop(GameSDKMain.this);\n    }\n\n    @Override\n    protected void onRestart() {\n        super.onRestart();\n        SDKAPI.getInstance().onRestart(GameSDKMain.this);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        SDKAPI.getInstance().onDestroy(GameSDKMain.this);\n    }\n\n    @Override\n    protected void onNewIntent(Intent intent) {\n        super.onNewIntent(intent);\n        SDKAPI.getInstance().onNewIntent(GameSDKMain.this,intent);\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        SDKAPI.getInstance().onActivityResult(GameSDKMain.this,requestCode,resultCode,data);\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        SDKAPI.getInstance().onRequestPermissionsResult(GameSDKMain.this,requestCode, permissions, grantResults);\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/white\"\n    android:paddingTop=\"10dp\"\n    android:paddingLeft=\"10dp\"\n    android:paddingRight=\"10dp\"\n    android:paddingBottom=\"10dp\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:orientation=\"horizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <Button\n                android:id=\"@+id/btn_login\"\n                android:layout_width=\"200dp\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"登录\" />\n\n            <Button\n                android:id=\"@+id/btn_switchAccount\"\n                android:layout_width=\"200dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"3dp\"\n                android:text=\"切换账号\" />\n\n            <Button\n                android:id=\"@+id/btn_logout\"\n                android:layout_width=\"200dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"3dp\"\n                android:text=\"注销\" />\n\n            <EditText\n                android:id=\"@+id/et_inputPrice\"\n                android:layout_width=\"200dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"3dp\"\n                android:background=\"@android:drawable/edit_text\"\n                android:text=\"1\"\n                android:textColor=\"@color/colorPrimaryDark\" />\n\n            <Button\n                android:id=\"@+id/btn_pay\"\n                android:layout_width=\"200dp\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"支付\" />\n\n            <Button\n                android:id=\"@+id/btn_exit\"\n                android:layout_width=\"200dp\"\n                android:layout_marginTop=\"3dp\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"退出\" />\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\">\n            <View\n                android:layout_width=\"10dp\"\n                android:layout_height=\"match_parent\"/>\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n            <TextView\n                android:layout_marginTop=\"10dp\"\n                android:id=\"@+id/tvLog\"\n                android:hint=\"显示回调信息：\"\n                android:layout_width=\"match_parent\"\n                android:textColor=\"@color/black\"\n                android:layout_height=\"wrap_content\" />\n        </LinearLayout>\n\n    </LinearLayout>\n\n</ScrollView>\n"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n    <color name=\"white\">#FFFFFF</color>\n    <color name=\"black\">#000000</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">GameSDKFrame</string>\n</resources>\n"
  },
  {
    "path": "app/src/test/java/com/bzai/gamesdkframe/ExampleUnitTest.java",
    "content": "package com.bzai.gamesdkframe;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    \n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.3.3'\n        \n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Jun 25 10:10:07 CST 2018\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-4.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app',\n\n        //项目API\n        ':GameSDK_API',\n\n        //项目Project\n        ':GameSDK_Project_JuHe',\n        ':GameSDK_Project_Custom',\n\n        //渠道插件\n        ':GameSDK_Channel_Test',\n        ':GameSDK_Channel_Lexiang',\n\n        //功能Module插件\n        ':GameSDK_Module_Init',\n        ':GameSDK_Module_Account',\n        ':GameSDK_Module_Purchase',\n\n        //功能插件\n        ':GameSDK_Manager_Impl',\n        ':GameSDK_Plugin_Alipay',\n        ':GameSDK_Plugin_Wechat',\n\n        //基础库\n        ':GameSDK_Utils',\n\n        // 编译生成Jar工具\n        ':GameSDKBuildJarTool',\n\n        ':GameSDKDemo_Release',\n        ':GameSDKLibrary_Release'\n\n/***\n * 后续新建一个Library Module 后拷贝到对应的目录就可以了,\n * 然后替换成对应的工程目录，或者新添加的工程目录。Clean下\n */\n\n//项目API工程,可根据需求修改\nproject(':GameSDK_API').projectDir = new File('GameSDK_API')\n\n\n//项目Project工程,可根据需求修改\nproject(':GameSDK_Project_JuHe').projectDir = new File('GameSDK_BeginProject/GameSDK_Project_JuHe')\nproject(':GameSDK_Project_Custom').projectDir = new File('GameSDK_BeginProject/GameSDK_Project_Custom')\n\n\n//项目Channel工程,可根据需求修改\nproject(':GameSDK_Channel_Test').projectDir = new File('GameSDK_Channel/GameSDK_Channel_Test')\nproject(':GameSDK_Channel_Lexiang').projectDir = new File('GameSDK_Channel/GameSDK_Channel_Lexiang')\n\n\n//项目Manager_Module工程,可根据需求修改\nproject(':GameSDK_Module_Init').projectDir = new File('GameSDK_Manager/GameSDK_Module_Init')\nproject(':GameSDK_Module_Account').projectDir = new File('GameSDK_Manager/GameSDK_Module_Account')\nproject(':GameSDK_Module_Purchase').projectDir = new File('GameSDK_Manager/GameSDK_Module_Purchase')\n\n\n//项目Plugin工程,可根据需求修改\nproject(':GameSDK_Manager_Impl').projectDir = new File('GameSDK_Manager_Impl')\nproject(':GameSDK_Plugin_Alipay').projectDir = new File('GameSDK_Plugin/GameSDK_Plugin_Alipay')\nproject(':GameSDK_Plugin_Wechat').projectDir = new File('GameSDK_Plugin/GameSDK_Plugin_Wechat')\n\n\n//基础库\nproject(':GameSDK_Utils').projectDir = new File('GameSDK_Utils')"
  },
  {
    "path": "框架必读说明",
    "content": "\n----------------------------------------------------------------------------------------------\n\nGameSDK_API层:\n\n   SDK对外接口层：是暴露给CP的接口,底层返回的数据格式在这一层转化,该层不参与混淆。\n                 所以不要在该层做业务逻辑处理，避免被反射调用修改。\n\n   后续有新的接口，可以在该层做拓展对外给CP。\n\n----------------------------------------------------------------------------------------------\n\nGameSDK_BeginProject层:\n\n   SDK项目层：是与Api层对接的项目入口层，可以通过修改配置文件 Project_config.txt\n   进入和替换成不同的Project SDK项目。\n\n   注意：\n\n       顶层Project已经确定好后，不要修改太多，如果有拓展的功能接口，\n       可以通过extendFunction()对应type拓展，避免改动太多底层代码。\n\n\n    SDK大体分为两类：\n    1、Project_JuHe为聚合SDK项目,主要业务用于封装三方渠道。\n\n    2、Project_Custom为自定义SDK项目,主要是做自己的渠道,每个公司可能会有不同的名称,\n       主要业务是,实现用户入口、支付逻辑、数据统计等功能。\n\n       可能根据不同的游戏运营需求会有不同的登录逻辑、绑定逻辑、支付方式、数据上报等\n       会细分为公版项目、海外项目(针对地区)、根据游戏的定制化项目等。可根据不同的项目,拓展Project\n\n\n    该层是做业务逻辑处理的，希望能有清晰的架构思路。\n\t\n----------------------------------------------------------------------------------------------\n\nSYSDK_Channel: SDK项目渠道层\n\n   该层负责对接渠道接入的业务，不同的渠道都会有对应的Module实现具体的代码调用和逻辑处理，以及资源配置\n   通过配置文件 Channel_config.txt 管理。\n\n   而且每个渠道Module都会有对应的开发者说明文件，方便后续的开发同事维护更新。详见开发者说明。\n\n   开发者格式说明：\n\n      格式： 渠道名 -- 版本号 -- 开发人员 （如果渠道没有版本就按V1.0.0来）    日期\n\n                相关注意事项说明：\n                1、.... xxx ....\n                2、.... xxx ....\n\n\n----------------------------------------------------------------------------------------------\n\nSYSDK_Manager:\n\n   SDK逻辑管理层：\n\n      该层为整个SDK功能逻辑的实现：初始化、账号、支付、获取道具信息、补单逻辑、退出\n      为避免逻辑层因业务太乱导致代码过多,及后续的功能模块抽离.\n      采用模块化化思想进行模块管理.\n\n      初始化：SDK初始化(全局参数缓存、环境切换、权限问题等) >- 项目初始化(默认初始化 和 项目初始化)\n\n      登陆：设备登陆、游客登录、账号登陆、三方登陆(google/facebook/微信)\n\n      支付：三方支付：google、支付宝、微信、及特有的项目支付、补单\n\n      退出：\n\n      当有额外的功能添加的时候，在该层实现即可。\n\n----------------------------------------------------------------------------------------------\n\nGameSDK_Manager_Impl:\n\n   SDK逻辑功能拓展反射层，通过反射解耦插件：\n\n        该层更多的是针对后续Plugin插件做不同的功能反射，具体调用Plugin层插件。\n        只负责对接GameSDK_Manager_Impl 和 Plugin插件层。\n\n----------------------------------------------------------------------------------------------\n\nGameSDK_Plugin:\n\n    SDK功能插件层，与渠道层有点类似，通过配置文件 Plugin_config.txt 管理。\n    通过逻辑控制层 Manager_Logic_Impl 反射调用实现，把插件拔除不影响。\n    可以是三方的功能插件，也可以是自己实现的插件。\n\n    目前为说明功能，用支付宝和微信说明\n    Alipay功能插件层：实现Alipay功能，封装Alipay相关接口\n    Wechat功能插件层：实现Wechat功能，封装Wechat相关接口\n\n   当有额外的功能添加的时候，在该层实现即可。\n   \n----------------------------------------------------------------------------------------------\n\nGameSDK_Utils:\n\n   GameSDK_Utils层：该层为整个SDK功能基础库：目前分为业务基础库 和 功能基础库，方便后续将业务分离。\n\n      基础组件：\n\n         1、数据缓存、域名配置、项目/插件/渠道管理\n            注意：将项目、渠道、插件分别加载的目的：\n\n            是为了快速替换项目Project的入口类\n\n            一个项目Project 可以对应多个渠道、多个插件。后续可以在多渠道、多插件上\n            进行快速的插拔和后台开关的切换渠道。\n\n            不过正常的需求都是一个项目，对应零个或一个渠道、一个或多个功能插件\n\n\n         2、网络请求、日志输出、Gson解析\n\n            注意：网络请求，目前封装的volly (volly是比较轻量级的，主要是为减少SDK包体)\n                 日志输出，目前封装的logger(logger比较轻量级，主要用于开发日志信息输出)\n\n                 第三方库快速替换方案思路：(方便后续维护替换成更好的库)\n                 接口解耦封装，实现上层业务网络请求接口不改动，只做封装层的api调用即可\n\n\n   基础库不要轻易修改! 不要轻易修改! 不要轻易修改! 不要轻易修改! 不要轻易修改!\n\n---------------------------------------------------------------------------------------\n\n"
  }
]