[
  {
    "path": ".gitignore",
    "content": ".gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n"
  },
  {
    "path": ".idea/.name",
    "content": "Notes"
  },
  {
    "path": ".idea/compiler.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"CompilerConfiguration\">\n    <option name=\"DEFAULT_COMPILER\" value=\"Javac\" />\n    <resourceExtensions />\n    <wildcardResourcePatterns>\n      <entry name=\"!?*.java\" />\n      <entry name=\"!?*.form\" />\n      <entry name=\"!?*.class\" />\n      <entry name=\"!?*.groovy\" />\n      <entry name=\"!?*.scala\" />\n      <entry name=\"!?*.flex\" />\n      <entry name=\"!?*.kt\" />\n      <entry name=\"!?*.clj\" />\n    </wildcardResourcePatterns>\n    <annotationProcessing>\n      <profile default=\"true\" name=\"Default\" enabled=\"false\">\n        <processorPath useClasspath=\"true\" />\n      </profile>\n    </annotationProcessing>\n  </component>\n</project>"
  },
  {
    "path": ".idea/copyright/profiles_settings.xml",
    "content": "<component name=\"CopyrightManager\">\n  <settings default=\"\" />\n</component>"
  },
  {
    "path": ".idea/encodings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"Encoding\">\n    <file url=\"PROJECT\" charset=\"UTF-8\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/gradle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GradleSettings\">\n    <option name=\"linkedExternalProjectsSettings\">\n      <GradleProjectSettings>\n        <option name=\"distributionType\" value=\"DEFAULT_WRAPPED\" />\n        <option name=\"externalProjectPath\" value=\"$PROJECT_DIR$\" />\n        <option name=\"gradleJvm\" value=\"1.8\" />\n        <option name=\"modules\">\n          <set>\n            <option value=\"$PROJECT_DIR$\" />\n            <option value=\"$PROJECT_DIR$/MaterialPreference\" />\n            <option value=\"$PROJECT_DIR$/app\" />\n            <option value=\"$PROJECT_DIR$/orm-library\" />\n          </set>\n        </option>\n      </GradleProjectSettings>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/misc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"EntryPointsManager\">\n    <entry_points version=\"2.0\" />\n  </component>\n  <component name=\"NullableNotNullManager\">\n    <option name=\"myDefaultNullable\" value=\"android.support.annotation.Nullable\" />\n    <option name=\"myDefaultNotNull\" value=\"android.support.annotation.NonNull\" />\n    <option name=\"myNullables\">\n      <value>\n        <list size=\"4\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.Nullable\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nullable\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.Nullable\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.Nullable\" />\n        </list>\n      </value>\n    </option>\n    <option name=\"myNotNulls\">\n      <value>\n        <list size=\"4\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.NotNull\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nonnull\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.NonNull\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.NonNull\" />\n        </list>\n      </value>\n    </option>\n  </component>\n  <component name=\"ProjectLevelVcsManager\" settingsEditedManually=\"false\">\n    <OptionsSetting value=\"true\" id=\"Add\" />\n    <OptionsSetting value=\"true\" id=\"Remove\" />\n    <OptionsSetting value=\"true\" id=\"Checkout\" />\n    <OptionsSetting value=\"true\" id=\"Update\" />\n    <OptionsSetting value=\"true\" id=\"Status\" />\n    <OptionsSetting value=\"true\" id=\"Edit\" />\n    <ConfirmationsSetting value=\"0\" id=\"Add\" />\n    <ConfirmationsSetting value=\"0\" id=\"Remove\" />\n  </component>\n  <component name=\"ProjectRootManager\" version=\"2\" languageLevel=\"JDK_1_7\" assert-keyword=\"true\" jdk-15=\"true\" project-jdk-name=\"1.8\" project-jdk-type=\"JavaSDK\">\n    <output url=\"file://$PROJECT_DIR$/build/classes\" />\n  </component>\n  <component name=\"ProjectType\">\n    <option name=\"id\" value=\"Android\" />\n  </component>\n  <component name=\"masterDetails\">\n    <states>\n      <state key=\"ProjectJDKs.UI\">\n        <settings>\n          <last-edited>1.7</last-edited>\n          <splitter-proportions>\n            <option name=\"proportions\">\n              <list>\n                <option value=\"0.2\" />\n              </list>\n            </option>\n          </splitter-proportions>\n        </settings>\n      </state>\n    </states>\n  </component>\n</project>"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/MaterialPreference/MaterialPreference.iml\" filepath=\"$PROJECT_DIR$/MaterialPreference/MaterialPreference.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/Notes.iml\" filepath=\"$PROJECT_DIR$/Notes.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/app/app.iml\" filepath=\"$PROJECT_DIR$/app/app.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/orm-library/orm-library.iml\" filepath=\"$PROJECT_DIR$/orm-library/orm-library.iml\" />\n    </modules>\n  </component>\n</project>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"$PROJECT_DIR$\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": "MaterialPreference/MaterialPreference.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.id=\":MaterialPreference\" external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$/..\" external.system.id=\"GRADLE\" external.system.module.group=\"Notes\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android-gradle\" name=\"Android-Gradle\">\n      <configuration>\n        <option name=\"GRADLE_PROJECT_PATH\" value=\":MaterialPreference\" />\n      </configuration>\n    </facet>\n    <facet type=\"android\" name=\"Android\">\n      <configuration>\n        <option name=\"SELECTED_BUILD_VARIANT\" value=\"debug\" />\n        <option name=\"SELECTED_TEST_ARTIFACT\" value=\"_android_test_\" />\n        <option name=\"ASSEMBLE_TASK_NAME\" value=\"assembleDebug\" />\n        <option name=\"COMPILE_JAVA_TASK_NAME\" value=\"compileDebugSources\" />\n        <option name=\"ASSEMBLE_TEST_TASK_NAME\" value=\"assembleDebugAndroidTest\" />\n        <option name=\"COMPILE_JAVA_TEST_TASK_NAME\" value=\"compileDebugAndroidTestSources\" />\n        <afterSyncTasks>\n          <task>generateDebugAndroidTestSources</task>\n          <task>generateDebugSources</task>\n        </afterSyncTasks>\n        <option name=\"ALLOW_USER_CONFIGURATION\" value=\"false\" />\n        <option name=\"MANIFEST_FILE_RELATIVE_PATH\" value=\"/src/main/AndroidManifest.xml\" />\n        <option name=\"RES_FOLDER_RELATIVE_PATH\" value=\"/src/main/res\" />\n        <option name=\"RES_FOLDERS_RELATIVE_PATH\" value=\"file://$MODULE_DIR$/src/main/res\" />\n        <option name=\"ASSETS_FOLDER_RELATIVE_PATH\" value=\"/src/main/assets\" />\n        <option name=\"LIBRARY_PROJECT\" value=\"true\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" LANGUAGE_LEVEL=\"JDK_1_7\" inherit-compiler-output=\"false\">\n    <output url=\"file://$MODULE_DIR$/build/intermediates/classes/debug\" />\n    <output-test url=\"file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug\" />\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/r/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/aidl/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/buildConfig/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/rs/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/rs/debug\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/generated/debug\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/r/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/res\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/assets\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/aidl\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/jni\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/rs\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/res\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/assets\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/aidl\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/jni\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/rs\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/res\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/resources\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/assets\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/aidl\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/java\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/jni\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/rs\" isTestSource=\"true\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/assets\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/bundles\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/classes\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dependency-cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dex\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dex-cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/22.2.0/jars\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/22.2.0/jars\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/exploded-aar/com.balysv/material-ripple/1.0.2/jars\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/incremental\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/jacoco\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/javaResources\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/libs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/lint\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/manifests\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/ndk\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/pre-dexed\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/proguard\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/res\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/rs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/symbols\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/outputs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/tmp\" />\n    </content>\n    <orderEntry type=\"jdk\" jdkName=\"Android API 22 Platform\" jdkType=\"Android SDK\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"support-annotations-22.2.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"support-v4-22.2.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"material-ripple-1.0.2\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"appcompat-v7-22.2.0\" level=\"project\" />\n  </component>\n</module>"
  },
  {
    "path": "MaterialPreference/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n  compileSdkVersion Integer.parseInt(ANDROID_BUILD_COMPILE_SDK_VERSION)\n  buildToolsVersion ANDROID_BUILD_TOOLS_VERSION\n\n  defaultConfig {\n    minSdkVersion Integer.parseInt(MIN_SDK_VERSION)\n    targetSdkVersion Integer.parseInt(ANDROID_BUILD_TARGET_SDK_VERSION)\n    versionCode Integer.parseInt(VERSION_CODE)\n    versionName VERSION_NAME\n  }\n\n  lintOptions {\n    abortOnError false\n  }\n}\n\ndependencies {\n  compile 'com.android.support:appcompat-v7:22.2.0'\n  compile 'com.balysv:material-ripple:1.0.2'\n}"
  },
  {
    "path": "MaterialPreference/src/main/AndroidManifest.xml",
    "content": "<manifest package=\"com.jenzz.materialpreference\"/>"
  },
  {
    "path": "MaterialPreference/src/main/java/com/jenzz/materialpreference/CheckBoxPreference.java",
    "content": "package com.jenzz.materialpreference;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.widget.CheckBox;\n\nimport static com.jenzz.materialpreference.ThemeUtils.isAtLeastL;\n\npublic class CheckBoxPreference extends TwoStatePreference {\n\n  public CheckBoxPreference(Context context) {\n    super(context);\n    init(context, null, 0, 0);\n  }\n\n  public CheckBoxPreference(Context context, AttributeSet attrs) {\n    super(context, attrs);\n    init(context, attrs, 0, 0);\n  }\n\n  public CheckBoxPreference(Context context, AttributeSet attrs, int defStyleAttr) {\n    super(context, attrs, defStyleAttr);\n    init(context, attrs, defStyleAttr, 0);\n  }\n\n  public CheckBoxPreference(Context context, AttributeSet attrs, int defStyleAttr,\n      int defStyleRes) {\n    super(context, attrs, defStyleAttr, defStyleRes);\n    init(context, attrs, defStyleAttr, defStyleRes);\n  }\n\n  private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n    TypedArray typedArray = context.obtainStyledAttributes(attrs, new int[] {\n        android.R.attr.summaryOn, android.R.attr.summaryOff, android.R.attr.disableDependentsState\n    }, defStyleAttr, defStyleRes);\n\n    setSummaryOn(typedArray.getString(0));\n    setSummaryOff(typedArray.getString(1));\n    setDisableDependentsState(typedArray.getBoolean(2, false));\n\n    typedArray.recycle();\n\n    setWidgetLayoutResource(R.layout.mp_checkbox_preference);\n  }\n\n  @Override @SuppressWarnings(\"deprecation\")\n  protected void onBindView(View view) {\n    super.onBindView(view);\n\n    CheckBox checkboxView = (CheckBox) view.findViewById(R.id.checkbox);\n    checkboxView.setChecked(isChecked());\n\n    if (isAtLeastL()) {\n      // remove circular background when pressed\n      checkboxView.setBackgroundDrawable(null);\n    }\n\n    syncSummaryView(view);\n  }\n}\n"
  },
  {
    "path": "MaterialPreference/src/main/java/com/jenzz/materialpreference/Preference.java",
    "content": "package com.jenzz.materialpreference;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.drawable.Drawable;\nimport android.util.AttributeSet;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport static android.content.Context.LAYOUT_INFLATER_SERVICE;\nimport static android.os.Build.VERSION_CODES.LOLLIPOP;\nimport static android.text.TextUtils.isEmpty;\nimport static android.view.View.GONE;\nimport static android.view.View.VISIBLE;\nimport static com.jenzz.materialpreference.Typefaces.getRobotoRegular;\n\npublic class Preference extends android.preference.Preference {\n\n  TextView titleView;\n  TextView summaryView;\n\n  ImageView imageView;\n  View imageFrame;\n\n  private int iconResId;\n  private Drawable icon;\n\n  public Preference(Context context) {\n    super(context);\n    init(context, null, 0, 0);\n  }\n\n  public Preference(Context context, AttributeSet attrs) {\n    super(context, attrs);\n    init(context, attrs, 0, 0);\n  }\n\n  public Preference(Context context, AttributeSet attrs, int defStyleAttr) {\n    super(context, attrs, defStyleAttr);\n    init(context, attrs, defStyleAttr, 0);\n  }\n\n  @TargetApi(LOLLIPOP)\n  public Preference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n    super(context, attrs, defStyleAttr, defStyleRes);\n    init(context, attrs, defStyleAttr, defStyleRes);\n  }\n\n  private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n    TypedArray typedArray =\n        context.obtainStyledAttributes(attrs, new int[] { android.R.attr.icon }, defStyleAttr,\n            defStyleRes);\n    iconResId = typedArray.getResourceId(0, 0);\n    typedArray.recycle();\n  }\n\n  @Override\n  protected View onCreateView(ViewGroup parent) {\n    LayoutInflater layoutInflater =\n        (LayoutInflater) getContext().getSystemService(LAYOUT_INFLATER_SERVICE);\n    View layout = layoutInflater.inflate(R.layout.mp_preference, parent, false);\n\n    ViewGroup widgetFrame = (ViewGroup) layout.findViewById(R.id.widget_frame);\n    int widgetLayoutResId = getWidgetLayoutResource();\n    if (widgetLayoutResId != 0) {\n      layoutInflater.inflate(widgetLayoutResId, widgetFrame);\n    }\n    widgetFrame.setVisibility(widgetLayoutResId != 0 ? VISIBLE : GONE);\n\n    return layout;\n  }\n\n  @Override\n  protected void onBindView(View view) {\n    super.onBindView(view);\n\n    CharSequence title = getTitle();\n    titleView = (TextView) view.findViewById(R.id.title);\n    titleView.setText(title);\n    titleView.setVisibility(!isEmpty(title) ? VISIBLE : GONE);\n    titleView.setTypeface(getRobotoRegular(getContext()));\n\n    CharSequence summary = getSummary();\n    summaryView = (TextView) view.findViewById(R.id.summary);\n    summaryView.setText(summary);\n    summaryView.setVisibility(!isEmpty(summary) ? VISIBLE : GONE);\n    summaryView.setTypeface(getRobotoRegular(getContext()));\n\n    if (icon == null && iconResId > 0) {\n      icon = getContext().getResources().getDrawable(iconResId);\n    }\n    imageView = (ImageView) view.findViewById(R.id.icon);\n    imageView.setImageDrawable(icon);\n    imageView.setVisibility(icon != null ? VISIBLE : GONE);\n\n    imageFrame = view.findViewById(R.id.icon_frame);\n    imageFrame.setVisibility(icon != null ? VISIBLE : GONE);\n  }\n\n  @Override\n  public void setIcon(int iconResId) {\n    super.setIcon(iconResId);\n    this.iconResId = iconResId;\n  }\n\n  @Override\n  public void setIcon(Drawable icon) {\n    super.setIcon(icon);\n    this.icon = icon;\n  }\n}\n"
  },
  {
    "path": "MaterialPreference/src/main/java/com/jenzz/materialpreference/PreferenceCategory.java",
    "content": "package com.jenzz.materialpreference;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport static android.content.Context.LAYOUT_INFLATER_SERVICE;\nimport static android.os.Build.VERSION_CODES.LOLLIPOP;\nimport static android.text.TextUtils.isEmpty;\nimport static android.view.View.GONE;\nimport static android.view.View.VISIBLE;\nimport static com.jenzz.materialpreference.ThemeUtils.resolveAccentColor;\nimport static com.jenzz.materialpreference.Typefaces.getRobotoMedium;\n\npublic class PreferenceCategory extends android.preference.PreferenceCategory {\n\n  private int accentColor;\n\n  public PreferenceCategory(Context context) {\n    super(context);\n    init();\n  }\n\n  public PreferenceCategory(Context context, AttributeSet attrs) {\n    super(context, attrs);\n    init();\n  }\n\n  public PreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr) {\n    super(context, attrs, defStyleAttr);\n    init();\n  }\n\n  @TargetApi(LOLLIPOP)\n  public PreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr,\n      int defStyleRes) {\n    super(context, attrs, defStyleAttr, defStyleRes);\n    init();\n  }\n\n  private void init() {\n    accentColor = resolveAccentColor(getContext());\n  }\n\n  @Override\n  protected View onCreateView(ViewGroup parent) {\n    LayoutInflater layoutInflater =\n        (LayoutInflater) getContext().getSystemService(LAYOUT_INFLATER_SERVICE);\n    return layoutInflater.inflate(R.layout.mp_preference_category, parent, false);\n  }\n\n  @Override\n  protected void onBindView(View view) {\n    super.onBindView(view);\n\n    CharSequence title = getTitle();\n    TextView titleView = (TextView) view.findViewById(R.id.title);\n    titleView.setText(title);\n    titleView.setTextColor(accentColor);\n    titleView.setVisibility(!isEmpty(title) ? VISIBLE : GONE);\n    titleView.setTypeface(getRobotoMedium(getContext()));\n  }\n}\n"
  },
  {
    "path": "MaterialPreference/src/main/java/com/jenzz/materialpreference/PreferenceImageView.java",
    "content": "package com.jenzz.materialpreference;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.widget.ImageView;\n\nimport static android.os.Build.VERSION_CODES.LOLLIPOP;\nimport static android.view.View.MeasureSpec.AT_MOST;\nimport static android.view.View.MeasureSpec.UNSPECIFIED;\nimport static android.view.View.MeasureSpec.getMode;\nimport static android.view.View.MeasureSpec.getSize;\nimport static android.view.View.MeasureSpec.makeMeasureSpec;\nimport static java.lang.Integer.MAX_VALUE;\n\n/**\n * Extension of ImageView that correctly applies maxWidth and maxHeight.\n */\npublic class PreferenceImageView extends ImageView {\n\n  private int maxWidth = MAX_VALUE;\n  private int maxHeight = MAX_VALUE;\n\n  public PreferenceImageView(Context context) {\n    super(context);\n  }\n\n  public PreferenceImageView(Context context, AttributeSet attrs) {\n    super(context, attrs);\n  }\n\n  public PreferenceImageView(Context context, AttributeSet attrs, int defStyleAttr) {\n    super(context, attrs, defStyleAttr);\n  }\n\n  @TargetApi(LOLLIPOP)\n  public PreferenceImageView(Context context, AttributeSet attrs, int defStyleAttr,\n      int defStyleRes) {\n    super(context, attrs, defStyleAttr, defStyleRes);\n  }\n\n  @Override\n  public void setMaxWidth(int maxWidth) {\n    super.setMaxWidth(maxWidth);\n    this.maxWidth = maxWidth;\n  }\n\n  @Override\n  public void setMaxHeight(int maxHeight) {\n    super.setMaxHeight(maxHeight);\n    this.maxHeight = maxHeight;\n  }\n\n  @Override\n  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n    int widthMode = getMode(widthMeasureSpec);\n    if (widthMode == AT_MOST || widthMode == UNSPECIFIED) {\n      int widthSize = getSize(widthMeasureSpec);\n      if (maxWidth != MAX_VALUE && (maxWidth < widthSize || widthMode == UNSPECIFIED)) {\n        widthMeasureSpec = makeMeasureSpec(maxWidth, AT_MOST);\n      }\n    }\n\n    int heightMode = getMode(heightMeasureSpec);\n    if (heightMode == AT_MOST || heightMode == UNSPECIFIED) {\n      int heightSize = getSize(heightMeasureSpec);\n      if (maxHeight != MAX_VALUE && (maxHeight < heightSize || heightMode == UNSPECIFIED)) {\n        heightMeasureSpec = makeMeasureSpec(maxHeight, AT_MOST);\n      }\n    }\n\n    super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n  }\n}"
  },
  {
    "path": "MaterialPreference/src/main/java/com/jenzz/materialpreference/SwitchPreference.java",
    "content": "package com.jenzz.materialpreference;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.support.v7.widget.SwitchCompat;\nimport android.util.AttributeSet;\nimport android.view.View;\n\npublic class SwitchPreference extends TwoStatePreference {\n\n  public SwitchPreference(Context context) {\n    super(context);\n    init(context, null, 0, 0);\n  }\n\n  public SwitchPreference(Context context, AttributeSet attrs) {\n    super(context, attrs);\n    init(context, attrs, 0, 0);\n  }\n\n  public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {\n    super(context, attrs, defStyleAttr);\n    init(context, attrs, defStyleAttr, 0);\n  }\n\n  public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n    super(context, attrs, defStyleAttr, defStyleRes);\n    init(context, attrs, defStyleAttr, defStyleRes);\n  }\n\n  private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n    TypedArray typedArray = context.obtainStyledAttributes(attrs, new int[] {\n        android.R.attr.summaryOn, android.R.attr.summaryOff, android.R.attr.disableDependentsState\n    }, defStyleAttr, defStyleRes);\n\n    setSummaryOn(typedArray.getString(0));\n    setSummaryOff(typedArray.getString(1));\n    setDisableDependentsState(typedArray.getBoolean(2, false));\n\n    typedArray.recycle();\n\n    setWidgetLayoutResource(R.layout.mp_switch_preference);\n  }\n\n  @Override\n  protected void onBindView(View view) {\n    super.onBindView(view);\n\n    SwitchCompat switchCompat = (SwitchCompat) view.findViewById(R.id.switch_compat);\n    switchCompat.setChecked(isChecked());\n\n    syncSummaryView(view);\n  }\n}\n"
  },
  {
    "path": "MaterialPreference/src/main/java/com/jenzz/materialpreference/ThemeUtils.java",
    "content": "package com.jenzz.materialpreference;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content.res.Resources.Theme;\nimport android.content.res.TypedArray;\n\nimport static android.graphics.Color.parseColor;\nimport static android.os.Build.VERSION.SDK_INT;\nimport static android.os.Build.VERSION_CODES.LOLLIPOP;\n\nfinal class ThemeUtils {\n\n  // material_deep_teal_500\n  static final int FALLBACK_COLOR = parseColor(\"#009688\");\n\n  private ThemeUtils() {\n    // no instances\n  }\n\n  static boolean isAtLeastL() {\n    return SDK_INT >= LOLLIPOP;\n  }\n\n  @TargetApi(LOLLIPOP)\n  static int resolveAccentColor(Context context) {\n    Theme theme = context.getTheme();\n\n    // on Lollipop, grab system colorAccent attribute\n    // pre-Lollipop, grab AppCompat colorAccent attribute\n    // finally, check for custom mp_colorAccent attribute\n    int attr = isAtLeastL() ? android.R.attr.colorAccent : R.attr.colorAccent;\n    TypedArray typedArray = theme.obtainStyledAttributes(new int[] { attr, R.attr.mp_colorAccent });\n\n    int accentColor = typedArray.getColor(0, FALLBACK_COLOR);\n    accentColor = typedArray.getColor(1, accentColor);\n    typedArray.recycle();\n\n    return accentColor;\n  }\n\n}\n"
  },
  {
    "path": "MaterialPreference/src/main/java/com/jenzz/materialpreference/TwoStatePreference.java",
    "content": "package com.jenzz.materialpreference;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.res.TypedArray;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport static android.text.TextUtils.isEmpty;\n\npublic abstract class TwoStatePreference extends Preference {\n\n  private CharSequence summaryOn;\n  private CharSequence summaryOff;\n  private boolean isChecked;\n  private boolean isCheckedSet;\n  private boolean disableDependentsState;\n\n  public TwoStatePreference(Context context) {\n    super(context);\n  }\n\n  public TwoStatePreference(Context context, AttributeSet attrs) {\n    super(context, attrs);\n  }\n\n  public TwoStatePreference(Context context, AttributeSet attrs, int defStyleAttr) {\n    super(context, attrs, defStyleAttr);\n  }\n\n  public TwoStatePreference(Context context, AttributeSet attrs, int defStyleAttr,\n      int defStyleRes) {\n    super(context, attrs, defStyleAttr, defStyleRes);\n  }\n\n  @Override\n  protected void onClick() {\n    super.onClick();\n\n    boolean newValue = !isChecked();\n    if (callChangeListener(newValue)) {\n      setChecked(newValue);\n    }\n  }\n\n  /**\n   * Sets the checked state and saves it to the {@link SharedPreferences}.\n   *\n   * @param checked\n   *     The checked state.\n   */\n  public void setChecked(boolean checked) {\n    // Always persist/notify the first time; don't assume the field's default of false.\n    boolean changed = isChecked != checked;\n    if (changed || !isCheckedSet) {\n      isChecked = checked;\n      isCheckedSet = true;\n      persistBoolean(checked);\n      if (changed) {\n        notifyDependencyChange(shouldDisableDependents());\n        notifyChanged();\n      }\n    }\n  }\n\n  /**\n   * Returns the checked state.\n   *\n   * @return The checked state.\n   */\n  public boolean isChecked() {\n    return isChecked;\n  }\n\n  @Override\n  public boolean shouldDisableDependents() {\n    boolean shouldDisable = disableDependentsState ? isChecked : !isChecked;\n    return shouldDisable || super.shouldDisableDependents();\n  }\n\n  /**\n   * Sets the summary to be shown when checked.\n   *\n   * @param summary\n   *     The summary to be shown when checked.\n   */\n  public void setSummaryOn(CharSequence summary) {\n    summaryOn = summary;\n    if (isChecked()) {\n      notifyChanged();\n    }\n  }\n\n  /**\n   * @param summaryResId\n   *     The summary as a resource.\n   *\n   * @see #setSummaryOn(CharSequence)\n   */\n  public void setSummaryOn(int summaryResId) {\n    setSummaryOn(getContext().getString(summaryResId));\n  }\n\n  /**\n   * Returns the summary to be shown when checked.\n   *\n   * @return The summary.\n   */\n  public CharSequence getSummaryOn() {\n    return summaryOn;\n  }\n\n  /**\n   * Sets the summary to be shown when unchecked.\n   *\n   * @param summary\n   *     The summary to be shown when unchecked.\n   */\n  public void setSummaryOff(CharSequence summary) {\n    summaryOff = summary;\n    if (!isChecked()) {\n      notifyChanged();\n    }\n  }\n\n  /**\n   * @param summaryResId\n   *     The summary as a resource.\n   *\n   * @see #setSummaryOff(CharSequence)\n   */\n  public void setSummaryOff(int summaryResId) {\n    setSummaryOff(getContext().getString(summaryResId));\n  }\n\n  /**\n   * Returns the summary to be shown when unchecked.\n   *\n   * @return The summary.\n   */\n  public CharSequence getSummaryOff() {\n    return summaryOff;\n  }\n\n  /**\n   * Returns whether dependents are disabled when this preference is on ({@code true})\n   * or when this preference is off ({@code false}).\n   *\n   * @return Whether dependents are disabled when this preference is on ({@code true})\n   * or when this preference is off ({@code false}).\n   */\n  public boolean getDisableDependentsState() {\n    return disableDependentsState;\n  }\n\n  /**\n   * Sets whether dependents are disabled when this preference is on ({@code true})\n   * or when this preference is off ({@code false}).\n   *\n   * @param disableDependentsState\n   *     The preference state that should disable dependents.\n   */\n  public void setDisableDependentsState(boolean disableDependentsState) {\n    this.disableDependentsState = disableDependentsState;\n  }\n\n  @Override\n  protected Object onGetDefaultValue(TypedArray a, int index) {\n    return a.getBoolean(index, false);\n  }\n\n  @Override\n  protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {\n    setChecked(restoreValue ? getPersistedBoolean(isChecked) : (Boolean) defaultValue);\n  }\n\n  /**\n   * Sync a summary view contained within view's subhierarchy with the correct summary text.\n   *\n   * @param view\n   *     View where a summary should be located\n   */\n  void syncSummaryView(View view) {\n    // Sync the summary view\n    boolean useDefaultSummary = true;\n    if (isChecked && !isEmpty(summaryOn)) {\n      summaryView.setText(summaryOn);\n      useDefaultSummary = false;\n    } else if (!isChecked && !isEmpty(summaryOff)) {\n      summaryView.setText(summaryOff);\n      useDefaultSummary = false;\n    }\n\n    if (useDefaultSummary) {\n      CharSequence summary = getSummary();\n      if (!isEmpty(summary)) {\n        summaryView.setText(summary);\n        useDefaultSummary = false;\n      }\n    }\n\n    int newVisibility = View.GONE;\n    if (!useDefaultSummary) {\n      // Someone has written to it\n      newVisibility = View.VISIBLE;\n    }\n    if (newVisibility != summaryView.getVisibility()) {\n      summaryView.setVisibility(newVisibility);\n    }\n  }\n\n  @Override\n  protected Parcelable onSaveInstanceState() {\n    Parcelable superState = super.onSaveInstanceState();\n    if (isPersistent()) {\n      // No need to save instance state since it's persistent\n      return superState;\n    }\n\n    SavedState myState = new SavedState(superState);\n    myState.checked = isChecked();\n    return myState;\n  }\n\n  @Override\n  protected void onRestoreInstanceState(Parcelable state) {\n    if (state == null || !state.getClass().equals(SavedState.class)) {\n      // Didn't save state for us in onSaveInstanceState\n      super.onRestoreInstanceState(state);\n      return;\n    }\n\n    SavedState myState = (SavedState) state;\n    super.onRestoreInstanceState(myState.getSuperState());\n    setChecked(myState.checked);\n  }\n\n  static class SavedState extends BaseSavedState {\n\n    boolean checked;\n\n    public SavedState(Parcel source) {\n      super(source);\n      checked = source.readInt() == 1;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n      super.writeToParcel(dest, flags);\n      dest.writeInt(checked ? 1 : 0);\n    }\n\n    public SavedState(Parcelable superState) {\n      super(superState);\n    }\n\n    public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {\n      public SavedState createFromParcel(Parcel in) {\n        return new SavedState(in);\n      }\n\n      public SavedState[] newArray(int size) {\n        return new SavedState[size];\n      }\n    };\n  }\n}\n\n"
  },
  {
    "path": "MaterialPreference/src/main/java/com/jenzz/materialpreference/Typefaces.java",
    "content": "package com.jenzz.materialpreference;\n\nimport android.content.Context;\nimport android.graphics.Typeface;\nimport android.util.Log;\nimport java.util.Hashtable;\n\nfinal class Typefaces {\n\n  private static final String TAG = Typefaces.class.getSimpleName();\n  private static final Hashtable<String, Typeface> cache = new Hashtable<>();\n\n  private Typefaces() {\n    // no instances\n  }\n\n  static Typeface get(Context context, String assetPath) {\n    synchronized (cache) {\n      if (!cache.containsKey(assetPath)) {\n        try {\n          Typeface t = Typeface.createFromAsset(context.getAssets(), assetPath);\n          cache.put(assetPath, t);\n        } catch (Exception e) {\n          Log.e(TAG, \"Could not get typeface '\" + assetPath + \"' Error: \" + e.getMessage());\n          return null;\n        }\n      }\n      return cache.get(assetPath);\n    }\n  }\n\n  static Typeface getRobotoRegular(Context context) {\n    return get(context, \"fonts/Roboto-Regular.ttf\");\n  }\n\n  static Typeface getRobotoMedium(Context context) {\n    return get(context, \"fonts/Roboto-Medium.ttf\");\n  }\n}\n"
  },
  {
    "path": "MaterialPreference/src/main/res/layout/mp_checkbox_preference.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<CheckBox xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/checkbox\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:focusable=\"false\"\n    android:clickable=\"false\"\n    />"
  },
  {
    "path": "MaterialPreference/src/main/res/layout/mp_preference.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.balysv.materialripple.MaterialRippleLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    app:mrl_rippleOverlay=\"true\"\n    app:mrl_rippleColor=\"?attr/colorPrimary\">\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:minHeight=\"48dp\"\n        android:gravity=\"center_vertical\"\n        android:paddingLeft=\"16dp\"\n        android:paddingRight=\"16dp\"\n        android:clipToPadding=\"false\"\n        >\n        <LinearLayout\n            android:id=\"@+id/icon_frame\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"-4dp\"\n            android:minWidth=\"60dp\"\n            android:gravity=\"start|center_vertical\"\n            android:orientation=\"horizontal\"\n            android:paddingRight=\"12dp\"\n            android:paddingTop=\"4dp\"\n            android:paddingBottom=\"4dp\"\n            >\n            <com.jenzz.materialpreference.PreferenceImageView\n                android:id=\"@+id/icon\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:maxWidth=\"48dp\"\n                android:maxHeight=\"48dp\"\n                />\n        </LinearLayout>\n\n        <RelativeLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:paddingTop=\"16dp\"\n            android:paddingBottom=\"16dp\"\n            >\n\n            <TextView\n                android:id=\"@+id/title\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textSize=\"16sp\"\n                android:textColor=\"?android:attr/textColorPrimary\"\n                android:ellipsize=\"marquee\"\n                />\n\n            <TextView\n                android:id=\"@+id/summary\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_below=\"@id/title\"\n                android:layout_alignLeft=\"@id/title\"\n                android:textSize=\"14sp\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:maxLines=\"10\"\n                />\n\n        </RelativeLayout>\n\n        <LinearLayout\n            android:id=\"@+id/widget_frame\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"end|center_vertical\"\n            android:paddingLeft=\"16dp\"\n            android:orientation=\"vertical\"\n            />\n\n    </LinearLayout>\n</com.balysv.materialripple.MaterialRippleLayout>\n"
  },
  {
    "path": "MaterialPreference/src/main/res/layout/mp_preference_category.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/title\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginBottom=\"16dp\"\n    android:textSize=\"14sp\"\n    android:paddingLeft=\"16dp\"\n    android:paddingRight=\"16dp\"\n    android:paddingTop=\"16dp\"\n    />"
  },
  {
    "path": "MaterialPreference/src/main/res/layout/mp_switch_preference.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v7.widget.SwitchCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/switch_compat\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@null\"\n    android:focusable=\"false\"\n    android:clickable=\"false\"\n    />"
  },
  {
    "path": "MaterialPreference/src/main/res/values/mp_attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n  <attr name=\"mp_colorAccent\"\n      format=\"reference|color\"/>\n\n</resources>"
  },
  {
    "path": "Notes.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.id=\"Notes\" external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$\" external.system.id=\"GRADLE\" external.system.module.group=\"\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"java-gradle\" name=\"Java-Gradle\">\n      <configuration>\n        <option name=\"BUILD_FOLDER_PATH\" value=\"$MODULE_DIR$/build\" />\n        <option name=\"BUILDABLE\" value=\"false\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" LANGUAGE_LEVEL=\"JDK_1_7\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <excludeFolder url=\"file://$MODULE_DIR$/.gradle\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": "README.md",
    "content": "#ScreenShot\n<img src=\"./screenshot/S50603-103314.jpg\" width=\"30%\" height=\"30%\">\n<img src=\"./screenshot/S50605-164248.jpg\" width=\"30%\" height=\"30%\">\n\n<img src=\"./screenshot/S50605-164615.jpg\" width=\"30%\" height=\"30%\">\n<img src=\"./screenshot/S50611-163425.jpg\" width=\"30%\" height=\"30%\">\n\n<img src=\"./screenshot/S50611-163752.jpg\" width=\"30%\" height=\"30%\">\n<img src=\"./screenshot/S50611-164132.jpg\" width=\"30%\" height=\"30%\">\n\n<img src=\"./screenshot/S50611-164146.jpg\" width=\"30%\" height=\"30%\">\n\n#1.1.2\n- 增加了多款彩色主题的选择\n- 增加了关于界面的分享功能\n- 修复了笔记过长的显示问题\n- 修复了SwipeRefreshLayout和RecyclerView的组合问题\n- 优化界面的一些细节，修复已知的小bug\n\n#1.1.0\n- 增加了笔记列表的卡片式的布局，可在设置里面切换\n- 增加了下拉同步笔记的组件\n- 增加编辑笔记时点击返回询问是否保存\n- 使用了Snackbar代替了Toast的提示\n- 去除了编辑笔记内容的下划线\n- 修改了笔记列表的显示时间方式\n- 修复了小米2s 5.0上CardView的显示问题\n\n#1.0.2\n- Material Design风格，采用抽屉式菜单，悬浮滑动按钮，点击控件时的水波纹效果，状态栏透明使得与应用融为一体，用户即使在Android L系统以下的手机也能感受到良好的用户体验\n- 用文字记录身边随时发生的事情，或者你的待办事项\n- 同步，同步需要你在手机设置里面添加一个邮箱，并作为你的同步账号，提交到服务器\n\n#License\n```\nCopyright 2015 Liaoguipeng\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/app.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.id=\":app\" external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$/..\" external.system.id=\"GRADLE\" external.system.module.group=\"Notes\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android-gradle\" name=\"Android-Gradle\">\n      <configuration>\n        <option name=\"GRADLE_PROJECT_PATH\" value=\":app\" />\n      </configuration>\n    </facet>\n    <facet type=\"android\" name=\"Android\">\n      <configuration>\n        <option name=\"SELECTED_BUILD_VARIANT\" value=\"debug\" />\n        <option name=\"SELECTED_TEST_ARTIFACT\" value=\"_android_test_\" />\n        <option name=\"ASSEMBLE_TASK_NAME\" value=\"assembleDebug\" />\n        <option name=\"COMPILE_JAVA_TASK_NAME\" value=\"compileDebugSources\" />\n        <option name=\"ASSEMBLE_TEST_TASK_NAME\" value=\"assembleDebugAndroidTest\" />\n        <option name=\"COMPILE_JAVA_TEST_TASK_NAME\" value=\"compileDebugAndroidTestSources\" />\n        <afterSyncTasks>\n          <task>generateDebugAndroidTestSources</task>\n          <task>generateDebugSources</task>\n        </afterSyncTasks>\n        <option name=\"ALLOW_USER_CONFIGURATION\" value=\"false\" />\n        <option name=\"MANIFEST_FILE_RELATIVE_PATH\" value=\"/src/main/AndroidManifest.xml\" />\n        <option name=\"RES_FOLDER_RELATIVE_PATH\" value=\"/src/main/res\" />\n        <option name=\"RES_FOLDERS_RELATIVE_PATH\" value=\"file://$MODULE_DIR$/src/main/res\" />\n        <option name=\"ASSETS_FOLDER_RELATIVE_PATH\" value=\"/src/main/assets\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" LANGUAGE_LEVEL=\"JDK_1_7\" inherit-compiler-output=\"false\">\n    <output url=\"file://$MODULE_DIR$/build/intermediates/classes/debug\" />\n    <output-test url=\"file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug\" />\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/r/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/aidl/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/buildConfig/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/rs/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/rs/debug\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/generated/debug\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/r/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/res\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/assets\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/aidl\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/jni\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/rs\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/res\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/assets\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/aidl\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/jni\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/rs\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/res\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/resources\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/assets\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/aidl\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/java\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/jni\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/rs\" isTestSource=\"true\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/assets\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/bundles\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/classes\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dependency-cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dex\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dex-cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/cardview-v7/22.2.0/jars\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/22.2.0/jars\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/exploded-aar/com.melnykov/floatingactionbutton/1.3.0/jars\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/exploded-aar/com.nispok/snackbar/2.10.10/jars\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/exploded-aar/com.pnikosis/materialish-progress/1.5/jars\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/exploded-aar/com.rengwuxian.materialedittext/library/2.1.3/jars\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/incremental\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/jacoco\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/javaResources\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/libs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/lint\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/manifests\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/ndk\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/pre-dexed\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/proguard\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/res\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/rs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/symbols\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/outputs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/reports\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/test-results\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/tmp\" />\n    </content>\n    <orderEntry type=\"jdk\" jdkName=\"Android API 22 Platform\" jdkType=\"Android SDK\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"library-2.4.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"fastjson\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"library-2.1.3\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"eventbus-2.4.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"recyclerview-v7-22.2.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"dagger-1.2.2\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"libammsdk\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"support-annotations-22.2.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"support-v4-22.2.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"materialish-progress-1.5\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"javax.inject-1\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"floatingactionbutton-1.3.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"guava-15.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"appcompat-v7-22.2.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"butterknife-6.1.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"BmobSDK_V3.3.8_0521\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"javawriter-2.5.0\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"systembartint-1.0.3\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"snackbar-2.10.10\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"dagger-compiler-1.2.2\" level=\"project\" />\n    <orderEntry type=\"library\" exported=\"\" name=\"cardview-v7-22.2.0\" level=\"project\" />\n    <orderEntry type=\"module\" module-name=\"MaterialPreference\" exported=\"\" />\n    <orderEntry type=\"module\" module-name=\"orm-library\" exported=\"\" />\n  </component>\n</module>"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\ndef packTime() {\n    return new Date().format(\"yyyyMMddHHmm\", TimeZone.getTimeZone(\"UTC\"))\n}\n\ndef projectUrl = \"https://github.com/lguipeng/Notes\"\ndef blogUrl = \"http://www.jianshu.com/users/f612d54d668e/latest_articles\"\ndef appDownloadUrl = \"http://notes.55058a091d225.d01.nanoyun.com/release/notes.apk\"\ndef aboutAppUrl = \"http://www.jianshu.com/p/640a7f2fe0c5\"\n\n//remember to add your bmob app key in local.properties\nProperties properties = new Properties()\nproperties.load(project.rootProject.file('local.properties').newDataInputStream())\ndef bmobAppKey = properties.getProperty('BMOB_KEY')\ndef weChatId = properties.getProperty('WECHAT_ID')\nandroid {\n    signingConfigs {\n        debug {\n\n        }\n        release {\n            //setting your signing.properties\n            //first, add signing.properties to ./app/\n            //second, add property STORE_FILE, STORE_PASSWORD, KEY_ALIAS, KEY_PASSWORD\n        }\n    }\n    compileSdkVersion Integer.parseInt(ANDROID_BUILD_COMPILE_SDK_VERSION)\n    buildToolsVersion ANDROID_BUILD_TOOLS_VERSION\n    defaultConfig {\n        applicationId \"com.lguipeng.notes\"\n        minSdkVersion Integer.parseInt(MIN_SDK_VERSION)\n        targetSdkVersion Integer.parseInt(ANDROID_BUILD_TARGET_SDK_VERSION)\n        versionCode Integer.parseInt(VERSION_CODE)\n        versionName VERSION_NAME\n\n        buildConfigField \"String\", \"BMOB_KEY\", \"\\\"${bmobAppKey}\\\"\"\n        buildConfigField \"String\", \"WECHAT_ID\", \"\\\"${weChatId}\\\"\"\n        buildConfigField \"String\", \"APP_DOWNLOAD_URL\", \"\\\"${appDownloadUrl}\\\"\"\n        buildConfigField \"String\", \"PROJECT_URL\", \"\\\"${projectUrl}\\\"\"\n        buildConfigField \"String\", \"BLOG_URL\", \"\\\"${blogUrl}\\\"\"\n        buildConfigField \"String\", \"ABOUT_APP_URL\", \"\\\"${aboutAppUrl}\\\"\"\n    }\n    buildTypes {\n\n        debug {\n            versionNameSuffix \" Beta\"\n            minifyEnabled false\n            zipAlignEnabled false\n            shrinkResources false\n            signingConfig signingConfigs.debug\n        }\n        release {\n            minifyEnabled false\n            zipAlignEnabled false\n            shrinkResources true\n            signingConfig signingConfigs.release\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    packagingOptions {\n        exclude 'META-INF/LICENSE.txt'\n        exclude 'META-INF/NOTICE.txt'\n    }\n    lintOptions {\n        abortOnError false\n    }\n\n    applicationVariants.all { variant ->\n        variant.outputs.each { output ->\n            def outputFile = output.outputFile\n            if (outputFile != null && outputFile.name.endsWith('.apk')) {\n                File outputDirectory = new File(outputFile.parent);\n                def fileName\n                if (variant.buildType.name == \"release\") {\n                    fileName = \"notes_v${defaultConfig.versionName}_${packTime()}.apk\"\n                }else{\n                    fileName = \"notes_beta.apk\"\n                }\n                output.outputFile = new File(outputDirectory, fileName)\n            }\n        }\n\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile 'com.android.support:support-v4:22.2.0'\n    compile 'com.android.support:appcompat-v7:22.2.0'\n    compile 'com.android.support:recyclerview-v7:22.2.0'\n    compile 'com.android.support:cardview-v7:22.2.0'\n    compile 'com.jakewharton:butterknife:6.1.0'\n    compile 'com.readystatesoftware.systembartint:systembartint:1.0.3'\n    compile 'com.melnykov:floatingactionbutton:1.3.0'\n    compile 'com.rengwuxian.materialedittext:library:2.1.3'\n    compile 'com.squareup.dagger:dagger:1.2.2'\n    provided 'com.squareup.dagger:dagger-compiler:1.2.2'\n    compile 'de.greenrobot:eventbus:2.4.0'\n    compile 'com.pnikosis:materialish-progress:1.5'\n    compile 'com.nispok:snackbar:2.10.10'\n    compile project(':orm-library')\n    compile project(':MaterialPreference')\n}\n\nFile propFile = file('signing.properties');\nif (propFile.exists()) {\n    def Properties props = new Properties()\n    props.load(new FileInputStream(propFile))\n    if (props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') &&\n            props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD')) {\n        android.signingConfigs.release.storeFile = file(props['STORE_FILE'])\n        android.signingConfigs.release.storePassword = props['STORE_PASSWORD']\n        android.signingConfigs.release.keyAlias = props['KEY_ALIAS']\n        android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']\n    } else {\n        android.buildTypes.release.signingConfig = null\n    }\n} else {\n    android.buildTypes.release.signingConfig = null\n}"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in E:\\adt-bundle-windows-x86_64-20131030/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\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"
  },
  {
    "path": "app/src/androidTest/java/com/lguipeng/notes/ApplicationTest.java",
    "content": "package com.lguipeng.notes;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" package=\"com.lguipeng.notes\">\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n    <application\n        android:name=\".App\"\n        android:allowBackup=\"true\"\n        android:label=\"@string/app_name\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:theme=\"@style/RedTheme\">\n\n        <activity\n            android:name=\".ui.MainActivity\"\n            android:launchMode=\"singleTop\"\n            android:screenOrientation=\"portrait\">\n            <meta-data\n                android:name=\"android.app.searchable\"\n                android:resource=\"@xml/searchable\" />\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEARCH\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".ui.SettingActivity\"\n            android:screenOrientation=\"portrait\"\n            android:launchMode=\"singleTop\">\n        </activity>\n\n        <activity\n            android:name=\".ui.NoteActivity\"\n            android:launchMode=\"singleTop\"\n            android:windowSoftInputMode=\"adjustResize|stateHidden\"\n            android:screenOrientation=\"portrait\">\n\n        </activity>\n        <activity\n            android:name=\".ui.AboutActivity\"\n            android:launchMode=\"singleTop\"\n            android:screenOrientation=\"portrait\">\n        </activity>\n\n        <activity\n            android:name=\".ui.PayActivity\"\n            android:launchMode=\"singleTop\"\n            android:screenOrientation=\"portrait\">\n        </activity>\n\n        <activity\n            android:name=\".ui.EditNoteTypeActivity\"\n            android:windowSoftInputMode=\"adjustResize\"\n            android:launchMode=\"singleTop\"\n            android:screenOrientation=\"portrait\">\n        </activity>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/App.java",
    "content": "package com.lguipeng.notes;\n\nimport android.app.Application;\n\nimport com.lguipeng.notes.module.AppModule;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport cn.bmob.v3.Bmob;\nimport dagger.ObjectGraph;\n\n/**\n * Created by lgp on 2015/5/24.\n */\npublic class App extends Application{\n    private ObjectGraph objectGraph;\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        objectGraph = ObjectGraph.create(getModules().toArray());\n        objectGraph.inject(this);\n        Bmob.initialize(this, BuildConfig.BMOB_KEY);\n    }\n\n    @Override\n    public void onTerminate() {\n        super.onTerminate();\n    }\n\n    @Override\n    public void onLowMemory() {\n        super.onLowMemory();\n    }\n\n    private List<Object> getModules() {\n        return Arrays.<Object>asList(new AppModule(this));\n    }\n\n    public ObjectGraph createScopedGraph(Object... modules) {\n        return objectGraph.plus(modules);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/adpater/BaseListAdapter.java",
    "content": "package com.lguipeng.notes.adpater;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\n@SuppressLint(\"UseSparseArrays\")\npublic abstract class BaseListAdapter<E> extends BaseAdapter {\n\n\tpublic List<E> list;\n\n\tpublic Context mContext;\n\n\tpublic LayoutInflater mInflater;\n\n\tpublic List<E> getList() {\n\t\treturn list;\n\t}\n\n\tpublic void setList(List<E> list) {\n\t\tthis.list = list;\n\t\tnotifyDataSetChanged();\n\t}\n\n\tpublic void add(E e) {\n\t\tthis.list.add(e);\n\t\tnotifyDataSetChanged();\n\t}\n\n\tpublic void addAll(List<E> list) {\n\t\tthis.list.addAll(list);\n\t\tnotifyDataSetChanged();\n\t}\n\n\tpublic void remove(int position) {\n\t\tthis.list.remove(position);\n\t\tnotifyDataSetChanged();\n\t}\n\n\tpublic BaseListAdapter(Context context, List<E> list) {\n\t\tsuper();\n\t\tthis.mContext = context;\n\t\tthis.list = list;\n\t\tmInflater = LayoutInflater.from(context);\n\t}\n\n\t@Override\n\tpublic int getCount() {\n\t\treturn list.size();\n\t}\n\n\t@Override\n\tpublic E getItem(int position) {\n\t\treturn list.get(position);\n\t}\n\n\t@Override\n\tpublic long getItemId(int position) {\n\t\treturn position;\n\t}\n\n\tpublic View getView(int position, View convertView, ViewGroup parent) {\n\t\tconvertView = bindView(position, convertView, parent);\n\t\taddInternalClickListener(convertView, position, list.get(position));\n\t\treturn convertView;\n\t}\n\n\tpublic abstract View bindView(int position, View convertView,\n\t\t\tViewGroup parent);\n\n\tpublic Map<Integer, onInternalClickListener<E>> canClickItem;\n\n\tprivate void addInternalClickListener(final View itemV, final Integer position, final E valuesMap) {\n\t\tif (canClickItem != null) {\n\t\t\tfor (Integer key : canClickItem.keySet()) {\n\t\t\t\tView inView = itemV.findViewById(key);\n\t\t\t\tfinal onInternalClickListener<E> listener = canClickItem.get(key);\n\t\t\t\tif (inView != null && listener != null) {\n\t\t\t\t\tinView.setOnClickListener(new OnClickListener() {\n\n\t\t\t\t\t\tpublic void onClick(View v) {\n\t\t\t\t\t\t\tlistener.OnClickListener(itemV, v, position,\n                                    valuesMap);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n                    inView.setOnLongClickListener(new View.OnLongClickListener() {\n                        @Override\n                        public boolean onLongClick(View v) {\n                            listener.OnLongClickListener(itemV, v, position,\n                                    valuesMap);\n                            return true;\n                        }\n                    });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic void setOnInViewClickListener(Integer key,\n\t\t\tonInternalClickListener<E> onClickListener) {\n\t\tif (canClickItem == null)\n\t\t\tcanClickItem = new HashMap<>();\n\t\tcanClickItem.put(key, onClickListener);\n\t}\n\n\tpublic interface onInternalClickListener<T> {\n\t\tvoid OnClickListener(View parentV, View v, Integer position,\n\t\t\t\t\t\t\t\t\tT values);\n\t\tvoid OnLongClickListener(View parentV, View v, Integer position,\n\t\t\t\t\t\t\t\t\t\tT values);\n\t}\n\n    public static class onInternalClickListenerImpl<T> implements onInternalClickListener<T>{\n        @Override\n        public void OnClickListener(View parentV, View v, Integer position, T values) {\n\n        }\n\n        @Override\n        public void OnLongClickListener(View parentV, View v, Integer position, T values) {\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/adpater/BaseRecyclerViewAdapter.java",
    "content": "package com.lguipeng.notes.adpater;\n\nimport android.animation.Animator;\nimport android.content.Context;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.animation.Interpolator;\nimport android.view.animation.LinearInterpolator;\n\nimport com.lguipeng.notes.utils.ViewHelper;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Created by lgp on 2015/5/24.\n */\npublic abstract class BaseRecyclerViewAdapter<E> extends RecyclerView.Adapter<RecyclerView.ViewHolder>{\n\n    protected Context mContext;\n\n    private int mDuration = 300;\n\n    private Interpolator mInterpolator = new LinearInterpolator();\n\n    private int mLastPosition = -1;\n\n    private boolean isFirstOnly = true;\n\n    protected List<E> list;\n    private Map<Integer, onInternalClickListener<E>> canClickItem;\n    public BaseRecyclerViewAdapter(List<E> list) {\n        this(list, null);\n    }\n\n    public BaseRecyclerViewAdapter(List<E> list, Context context) {\n        this.list = list;\n        this.mContext = context;\n    }\n\n    public void add(E e) {\n        this.list.add(0, e);\n        notifyItemInserted(0);\n    }\n\n    public void remove(E e) {\n        this.list.remove(e);\n        notifyDataSetChanged();\n    }\n\n    public void remove(int position) {\n        this.list.remove(position);\n        notifyDataSetChanged();\n    }\n\n\n    public void setList(List<E> list) {\n        this.list.clear();\n        this.list.addAll(list);\n        notifyDataSetChanged();\n    }\n\n    public List<E> getList() {\n        return list;\n    }\n\n    @Override\n    public int getItemCount() {\n        return list.size();\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        return null;\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {\n        if (holder != null){\n            addInternalClickListener(holder.itemView, position, list.get(position));\n        }\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return 1;\n    }\n\n    private void addInternalClickListener(final View itemV, final Integer position, final E valuesMap) {\n        if (canClickItem != null) {\n            for (Integer key : canClickItem.keySet()) {\n                View inView = itemV.findViewById(key);\n                final onInternalClickListener<E> listener = canClickItem.get(key);\n                if (inView != null && listener != null) {\n                    inView.setOnClickListener(new View.OnClickListener() {\n                        public void onClick(View v) {\n                            listener.OnClickListener(itemV, v, position,\n                                    valuesMap);\n\n                        }\n                    });\n                    inView.setOnLongClickListener(new View.OnLongClickListener() {\n                        @Override\n                        public boolean onLongClick(View v) {\n                            listener.OnLongClickListener(itemV, v, position,\n                                    valuesMap);\n                            return true;\n                        }\n                    });\n                }\n            }\n        }\n    }\n\n    public void setOnInViewClickListener(Integer key, onInternalClickListener<E> onClickListener) {\n        if (canClickItem == null)\n            canClickItem = new HashMap<>();\n        canClickItem.put(key, onClickListener);\n    }\n\n    public interface onInternalClickListener<T> {\n        void OnClickListener(View parentV, View v, Integer position,\n                                    T values);\n        void OnLongClickListener(View parentV, View v, Integer position,\n                                        T values);\n    }\n\n    public static class onInternalClickListenerImpl<T> implements onInternalClickListener<T>{\n        @Override\n        public void OnClickListener(View parentV, View v, Integer position, T values) {\n\n        }\n\n        @Override\n        public void OnLongClickListener(View parentV, View v, Integer position, T values) {\n\n        }\n    }\n\n    public void setDuration(int duration) {\n        mDuration = duration;\n    }\n\n    public void setInterpolator(Interpolator interpolator) {\n        mInterpolator = interpolator;\n    }\n\n    public void setStartPosition(int start) {\n        mLastPosition = start;\n    }\n\n    public void setFirstOnly(boolean firstOnly) {\n        isFirstOnly = firstOnly;\n    }\n\n    protected void animate(RecyclerView.ViewHolder holder, int position){\n        if (!isFirstOnly || position > mLastPosition) {\n            for (Animator anim : getAnimators(holder.itemView)) {\n                anim.setDuration(mDuration).start();\n                anim.setInterpolator(mInterpolator);\n\n            }\n            mLastPosition = position;\n        } else {\n            ViewHelper.clear(holder.itemView);\n        }\n    }\n\n    protected abstract Animator[] getAnimators(View view);\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/adpater/ColorsListAdapter.java",
    "content": "package com.lguipeng.notes.adpater;\n\nimport android.content.Context;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\n\nimport com.lguipeng.notes.R;\n\nimport java.util.List;\n\n/**\n * Created by lgp on 2015/6/7.\n */\npublic class ColorsListAdapter extends BaseListAdapter<Integer>{\n\n    private int checkItem;\n\n    public ColorsListAdapter(Context context, List<Integer> list) {\n        super(context, list);\n    }\n\n    @Override\n    public View bindView(int position, View convertView, ViewGroup parent) {\n        Holder holder;\n        if (convertView == null){\n            convertView = LayoutInflater.from(mContext).inflate(R.layout.colors_image_layout, null);\n            holder = new Holder();\n            holder.imageView1 = (ImageView)convertView.findViewById(R.id.img_1);\n            holder.imageView2 = (ImageView)convertView.findViewById(R.id.img_2);\n            convertView.setTag(holder);\n        }else{\n            holder = (Holder)convertView.getTag();\n        }\n        holder.imageView1.setImageResource(list.get(position));\n        if (checkItem == position){\n            holder.imageView2.setImageResource(R.drawable.ic_done_white);\n        }\n        return convertView;\n    }\n\n    public int getCheckItem() {\n        return checkItem;\n    }\n\n    public void setCheckItem(int checkItem) {\n        this.checkItem = checkItem;\n    }\n\n    static class Holder {\n        ImageView imageView1;\n        ImageView imageView2;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/adpater/DrawerListAdapter.java",
    "content": "package com.lguipeng.notes.adpater;\n\nimport android.content.Context;\n\nimport com.lguipeng.notes.R;\n\nimport java.util.List;\n\n/**\n * Created by lgp on 2015/5/24.\n */\npublic class DrawerListAdapter extends SimpleListAdapter{\n\n    public DrawerListAdapter(Context mContext, List<String> list) {\n        super(mContext, list);\n    }\n\n    @Override\n    protected int getLayout() {\n        return R.layout.drawer_list_item_layout;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/adpater/MaterialSimpleListAdapter.java",
    "content": "package com.lguipeng.notes.adpater;\n\nimport android.content.Context;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.lguipeng.notes.R;\nimport com.lguipeng.notes.model.MaterialSimpleListItem;\n\n/**\n * Created by lgp on 2015/6/10.\n */\npublic class MaterialSimpleListAdapter extends ArrayAdapter<MaterialSimpleListItem> {\n\n    public MaterialSimpleListAdapter(Context context) {\n        super(context, R.layout.md_simplelist_item, android.R.id.title);\n    }\n\n    @Override\n    public View getView(final int index, View convertView, ViewGroup parent) {\n        final View view = super.getView(index, convertView, parent);\n        final MaterialSimpleListItem item = getItem(index);\n        ImageView ic = (ImageView) view.findViewById(android.R.id.icon);\n        if (item.getIcon() != null)\n            ic.setImageDrawable(item.getIcon());\n        else\n            ic.setVisibility(View.GONE);\n        TextView tv = (TextView) view.findViewById(android.R.id.title);\n        tv.setText(item.getContent());\n        return view;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/adpater/NotesAdapter.java",
    "content": "package com.lguipeng.notes.adpater;\n\nimport android.animation.Animator;\nimport android.animation.ObjectAnimator;\nimport android.content.Context;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Filter;\nimport android.widget.Filterable;\n\nimport com.lguipeng.notes.R;\nimport com.lguipeng.notes.model.Note;\nimport com.lguipeng.notes.utils.TimeUtils;\n\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Created by lgp on 2015/4/6.\n */\npublic class NotesAdapter extends BaseRecyclerViewAdapter<Note> implements Filterable{\n    private final List<Note> originalList;\n    private int upDownFactor = 1;\n    private boolean isShowScaleAnimate = true;\n    public NotesAdapter(List<Note> list) {\n        super(list);\n        originalList = new ArrayList<>(list);\n    }\n\n    public NotesAdapter(List<Note> list, Context context) {\n        super(list, context);\n        originalList = new ArrayList<>(list);\n    }\n\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        Context context = parent.getContext();\n        final View view = LayoutInflater.from(context).inflate(R.layout.notes_item_layout, parent, false);\n        return new NotesItemViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {\n        super.onBindViewHolder(viewHolder, position);\n        NotesItemViewHolder holder = (NotesItemViewHolder) viewHolder;\n        Note note = list.get(position);\n        if (note == null)\n            return;\n        holder.setLabelText(note.getLabel());\n        holder.setContentText(note.getContent());\n        holder.setTimeText(TimeUtils.getConciseTime(note.getLastOprTime(), mContext));\n        animate(viewHolder, position);\n    }\n\n    @Override\n    public Filter getFilter() {\n        return new NoteFilter(this, originalList);\n    }\n\n    @Override\n    protected Animator[] getAnimators(View view) {\n        if (view.getMeasuredHeight() <=0 || isShowScaleAnimate){\n            ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, \"scaleX\", 1.1f, 1f);\n            ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, \"scaleY\", 1.1f, 1f);\n            return new ObjectAnimator[]{scaleX, scaleY};\n        }\n        return new Animator[]{\n                ObjectAnimator.ofFloat(view, \"scaleX\", 1.1f, 1f),\n                ObjectAnimator.ofFloat(view, \"scaleY\", 1.1f, 1f),\n                ObjectAnimator.ofFloat(view, \"translationY\", upDownFactor * 1.5f * view.getMeasuredHeight(), 0)\n        };\n    }\n\n    @Override\n    public void setList(List<Note> list) {\n        super.setList(list);\n        this.originalList.clear();\n        originalList.addAll(list);\n        setUpFactor();\n        isShowScaleAnimate = true;\n    }\n\n    public void setDownFactor(){\n        upDownFactor = -1;\n        isShowScaleAnimate = false;\n    }\n\n    public void setUpFactor(){\n        upDownFactor = 1;\n        isShowScaleAnimate = false;\n    }\n\n    private static class NoteFilter extends Filter{\n\n        private final NotesAdapter adapter;\n\n        private final List<Note> originalList;\n\n        private final List<Note> filteredList;\n\n        private NoteFilter(NotesAdapter adapter, List<Note> originalList) {\n            super();\n            this.adapter = adapter;\n            this.originalList = new LinkedList<>(originalList);\n            this.filteredList = new ArrayList<>();\n        }\n\n        @Override\n        protected FilterResults performFiltering(CharSequence constraint) {\n            filteredList.clear();\n            final FilterResults results = new FilterResults();\n            if (constraint.length() == 0) {\n                filteredList.addAll(originalList);\n            } else {\n                for ( Note note : originalList) {\n                    if (note.getContent().contains(constraint) || note.getLabel().contains(constraint)) {\n                        filteredList.add(note);\n                    }\n                }\n            }\n            results.values = filteredList;\n            results.count = filteredList.size();\n            return results;\n        }\n\n        @Override\n        protected void publishResults(CharSequence constraint, FilterResults results) {\n            adapter.list.clear();\n            adapter.list.addAll((ArrayList<Note>) results.values);\n            adapter.notifyDataSetChanged();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/adpater/NotesItemViewHolder.java",
    "content": "package com.lguipeng.notes.adpater;\n\nimport android.support.v7.widget.RecyclerView;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport com.lguipeng.notes.R;\n\n/**\n * Created by lgp on 2015/4/6.\n */\npublic class NotesItemViewHolder extends RecyclerView.ViewHolder{\n\n    private final TextView mNoteLabelTextView;\n    private final TextView mNoteContentTextView;\n    private final TextView mNoteTimeTextView;\n    public NotesItemViewHolder(View parent) {\n        super(parent);\n        mNoteLabelTextView = (TextView) parent.findViewById(R.id.note_label_text);\n        mNoteContentTextView = (TextView) parent.findViewById(R.id.note_content_text);\n        mNoteTimeTextView = (TextView) parent.findViewById(R.id.note_last_edit_text);\n    }\n\n    public void setLabelText(CharSequence text){\n        setTextView(mNoteLabelTextView, text);\n    }\n\n    public void setLabelText(int text){\n        setTextView(mNoteLabelTextView, text);\n    }\n\n    public void setContentText(CharSequence text){\n        setTextView(mNoteContentTextView, text);\n    }\n\n    public void setContentText(int text){\n        setTextView(mNoteContentTextView, text);\n    }\n\n    public void setTimeText(CharSequence text){\n        setTextView(mNoteTimeTextView, text);\n    }\n\n    public void setTimeText(int text){\n        setTextView(mNoteTimeTextView, text);\n    }\n\n    private void setTextView(TextView view, CharSequence text){\n        if (view == null || TextUtils.isEmpty(text))\n            return;\n        view.setText(text);\n    }\n\n    private void setTextView(TextView view, int text){\n        if (view == null || text <= 0)\n            return;\n        view.setText(text);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/adpater/SimpleListAdapter.java",
    "content": "package com.lguipeng.notes.adpater;\n\nimport android.content.Context;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport com.lguipeng.notes.R;\n\nimport java.util.List;\n\n/**\n * Created by lgp on 2014/8/27.\n */\npublic abstract class SimpleListAdapter extends BaseListAdapter<String> {\n\n    public SimpleListAdapter(Context mContext, List<String> list) {\n        super(mContext, list);\n    }\n\n    @Override\n    public View bindView(int position, View convertView, ViewGroup parent) {\n        Holder holder;\n        if (convertView == null){\n            convertView = LayoutInflater.from(mContext).inflate(getLayout(), null);\n            holder = new Holder();\n            holder.textView = (TextView)convertView.findViewById(R.id.textView);\n            convertView.setTag(holder);\n        }else{\n            holder = (Holder)convertView.getTag();\n        }\n        holder.textView.setText(list.get(position));\n        return convertView;\n    }\n\n    protected abstract int getLayout();\n\n    static class Holder {\n        TextView textView;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/listener/bmob/FindListenerImpl.java",
    "content": "package com.lguipeng.notes.listener.bmob;\n\nimport com.lguipeng.notes.utils.NotesLog;\n\nimport java.util.List;\n\nimport cn.bmob.v3.listener.FindListener;\n\n/**\n * Created by lgp on 2015/5/30.\n */\npublic class FindListenerImpl<T> extends FindListener<T> {\n    @Override\n    public void onSuccess(List<T> list) {\n\n    }\n\n    @Override\n    public void onError(int i, String s) {\n        NotesLog.e(s);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/listener/bmob/SaveListenerImpl.java",
    "content": "package com.lguipeng.notes.listener.bmob;\n\nimport com.lguipeng.notes.utils.NotesLog;\n\nimport cn.bmob.v3.listener.SaveListener;\n\n/**\n * Created by lgp on 2015/5/30.\n */\npublic class SaveListenerImpl extends SaveListener {\n    @Override\n    public void onSuccess() {\n\n    }\n\n    @Override\n    public void onFailure(int i, String s) {\n        NotesLog.e(s);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/listener/bmob/UpdateListenerImpl.java",
    "content": "package com.lguipeng.notes.listener.bmob;\n\nimport com.lguipeng.notes.utils.NotesLog;\n\nimport cn.bmob.v3.listener.UpdateListener;\n\n/**\n * Created by lgp on 2015/5/30.\n */\npublic class UpdateListenerImpl extends UpdateListener {\n    @Override\n    public void onSuccess() {\n\n    }\n\n    @Override\n    public void onFailure(int i, String s) {\n        NotesLog.e(s);\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/listener/view/RecyclerViewClickListener.java",
    "content": "package com.lguipeng.notes.listener.view;\n\nimport android.view.View;\n\n/**\n * Interface definition for a callback to be invoked when an item in a\n * RecyclerView has been clicked.\n */\npublic interface RecyclerViewClickListener {\n\n    /**\n     * Callback method to be invoked when a item in a\n     * RecyclerView is clicked\n     *  @param v The view within the RecyclerView.Adapter\n     * @param position The position of the view in the adapter\n     * @param x\n     * @param y\n     */\n    void onClick(View v, int position, float x, float y);\n}"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/model/CloudNote.java",
    "content": "package com.lguipeng.notes.model;\n\nimport com.lguipeng.notes.utils.JsonUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport cn.bmob.v3.BmobObject;\n\n/**\n * Created by lgp on 2015/5/28.\n */\npublic class CloudNote extends BmobObject {\n\n    public CloudNote() {\n        this(\"CloudNote\");\n    }\n\n    public CloudNote(String theClassName) {\n        super(theClassName);\n    }\n\n    private String email;\n\n    private List<String> noteList = new ArrayList<>();\n\n    private String noteType;\n\n    private long version;\n\n    public long getVersion() {\n        return version;\n    }\n\n    public void setVersion(long version) {\n        this.version = version;\n    }\n\n    public String getNoteType() {\n        return noteType;\n    }\n\n    public void setNoteType(String noteType) {\n        this.noteType = noteType;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public List<String> getNoteList() {\n        return noteList;\n    }\n\n    public void setNoteList(List<String> noteList) {\n        this.noteList = noteList;\n    }\n\n    public void addNote(Note note) {\n        noteList.add(JsonUtils.jsonNote(note));\n    }\n\n    public void clearNotes() {\n        noteList.clear();\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        //sb.append(super.toString());\n        //sb.append(\"\\n\");\n        for (String note : noteList){\n            sb.append(note);\n            sb.append(\"\\n\");\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/model/MaterialSimpleListItem.java",
    "content": "package com.lguipeng.notes.model;\n\nimport android.content.Context;\nimport android.graphics.drawable.Drawable;\nimport android.support.annotation.DrawableRes;\nimport android.support.annotation.StringRes;\nimport android.support.v4.content.ContextCompat;\n\n/**\n * Created by lgp on 2015/6/10.\n */\npublic class MaterialSimpleListItem {\n\n    private Builder mBuilder;\n\n    private MaterialSimpleListItem(Builder builder) {\n        mBuilder = builder;\n    }\n\n    public Drawable getIcon() {\n        return mBuilder.mIcon;\n    }\n\n    public CharSequence getContent() {\n        return mBuilder.mContent;\n    }\n\n    public static class Builder {\n\n        private Context mContext;\n        protected Drawable mIcon;\n        protected CharSequence mContent;\n\n        public Builder(Context context) {\n            mContext = context;\n        }\n\n        public Builder icon(Drawable icon) {\n            this.mIcon = icon;\n            return this;\n        }\n\n        public Builder icon(@DrawableRes int iconRes) {\n            if (iconRes == 0)\n                return this;\n            return icon(ContextCompat.getDrawable(mContext, iconRes));\n        }\n\n        public Builder content(CharSequence content) {\n            this.mContent = content;\n            return this;\n        }\n\n        public Builder content(@StringRes int contentRes) {\n            return content(mContext.getString(contentRes));\n        }\n\n        public MaterialSimpleListItem build() {\n            return new MaterialSimpleListItem(this);\n        }\n    }\n\n    @Override\n    public String toString() {\n        if (getContent() != null)\n            return getContent().toString();\n        else return \"(no content)\";\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/model/Note.java",
    "content": "package com.lguipeng.notes.model;\n\nimport com.alibaba.fastjson.annotation.JSONField;\nimport com.lguipeng.notes.utils.JsonUtils;\n\nimport net.tsz.afinal.annotation.sqlite.OneToMany;\nimport net.tsz.afinal.annotation.sqlite.Table;\nimport net.tsz.afinal.db.sqlite.OneToManyLazyLoader;\n\nimport java.io.Serializable;\n\n/**\n * Created by lgp on 2015/5/25.\n */\n@Table(name = \"notes\")\npublic class Note implements Serializable{\n    @JSONField(serialize=false, deserialize=false)\n    private int id;\n    private int type;\n    private String label;\n    private String content;\n    private long lastOprTime;\n    @JSONField(serialize=false, deserialize=false)\n    @OneToMany(manyColumn = \"noteId\")\n    private OneToManyLazyLoader<Note ,NoteOperateLog> logs;\n\n    public int getId() {\n        return id;\n    }\n\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    public String getLabel() {\n        return label;\n    }\n\n    public void setLabel(String label) {\n        this.label = label;\n    }\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n\n    public long getLastOprTime() {\n        return lastOprTime;\n    }\n\n    public void setLastOprTime(long lastOprTime) {\n        this.lastOprTime = lastOprTime;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public OneToManyLazyLoader<Note, NoteOperateLog> getLogs() {\n        return logs;\n    }\n\n    public void setLogs(OneToManyLazyLoader<Note, NoteOperateLog> logs) {\n        this.logs = logs;\n    }\n\n    @Override\n    public String toString() {\n        return JsonUtils.jsonNote(this);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/model/NoteOperateLog.java",
    "content": "package com.lguipeng.notes.model;\n\nimport net.tsz.afinal.annotation.sqlite.ManyToOne;\nimport net.tsz.afinal.annotation.sqlite.Table;\n\nimport java.io.Serializable;\n\n/**\n * Created by lgp on 2015/5/25.\n */\n@Table(name = \"note_opr_log\")\npublic class NoteOperateLog implements Serializable {\n    private int id;\n    private int type;\n    private long time;\n    @ManyToOne(column = \"noteId\")\n    private Note note;\n\n    public int getId() {\n        return id;\n    }\n\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public long getTime() {\n        return time;\n    }\n\n    public void setTime(long time) {\n        this.time = time;\n    }\n\n    public Note getNote() {\n        return note;\n    }\n\n    public void setNote(Note note) {\n        this.note = note;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/model/NoteType.java",
    "content": "package com.lguipeng.notes.model;\n\nimport android.text.TextUtils;\n\nimport com.alibaba.fastjson.annotation.JSONField;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by lgp on 2015/6/2.\n */\npublic class NoteType{\n\n    @JSONField(serialize=false, deserialize=false)\n    public final static int ALL_COUNT = 4;\n\n    private List<String> types = new ArrayList<>();\n\n    public void addType(String type){\n        if (types != null && types.size() < ALL_COUNT && !TextUtils.isEmpty(type)){\n            types.add(type);\n        }\n    }\n\n    public String getType(int location){\n        if (types != null && types.size() > location){\n            return types.get(location);\n        }\n        return \"\";\n    }\n\n    public List<String> getTypes() {\n        return types;\n    }\n\n    public void setTypes(List<String> types) {\n        this.types = types;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/module/AppModule.java",
    "content": "package com.lguipeng.notes.module;\n\nimport android.app.Application;\nimport android.content.Context;\n\nimport com.lguipeng.notes.App;\n\nimport dagger.Module;\nimport dagger.Provides;\n\n/**\n * Created by lgp on 2015/5/26.\n */\n@Module(\n        injects = {\n                App.class\n        },\n        library = true\n)\npublic class AppModule {\n    private App app;\n\n    public AppModule(App app) {\n        this.app = app;\n    }\n\n    @Provides\n    Application provideApplication() {\n        return app;\n    }\n\n    @Provides\n    Context provideContext() {\n        return app.getApplicationContext();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/module/DataModule.java",
    "content": "package com.lguipeng.notes.module;\n\nimport android.content.Context;\n\nimport com.lguipeng.notes.ui.AboutActivity;\nimport com.lguipeng.notes.ui.EditNoteTypeActivity;\nimport com.lguipeng.notes.ui.MainActivity;\nimport com.lguipeng.notes.ui.NoteActivity;\nimport com.lguipeng.notes.ui.PayActivity;\nimport com.lguipeng.notes.ui.SettingActivity;\nimport com.lguipeng.notes.ui.fragments.SettingFragment;\n\nimport net.tsz.afinal.FinalDb;\n\nimport javax.inject.Singleton;\n\nimport dagger.Module;\nimport dagger.Provides;\n\n/**\n * Created by lgp on 2015/5/26.\n */\n@Module(\n        injects = {\n                AboutActivity.class,\n                MainActivity.class,\n                NoteActivity.class,\n                SettingActivity.class,\n                SettingFragment.class,\n                PayActivity.class,\n                EditNoteTypeActivity.class\n        },\n        addsTo = AppModule.class,\n        library = true\n)\npublic class DataModule {\n\n    @Provides @Singleton\n    FinalDb.DaoConfig provideDaoConfig(Context context) {\n        FinalDb.DaoConfig config = new FinalDb.DaoConfig();\n        config.setDbName(\"notes.db\");\n        config.setDbVersion(1);\n        config.setDebug(true);\n        config.setContext(context);\n        return config;\n    }\n\n    @Provides @Singleton\n    FinalDb provideFinalDb(FinalDb.DaoConfig config) {\n        return FinalDb.create(config);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/ui/AboutActivity.java",
    "content": "package com.lguipeng.notes.ui;\n\nimport android.content.ActivityNotFoundException;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.support.v7.app.AlertDialog;\nimport android.support.v7.widget.Toolbar;\nimport android.text.TextUtils;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.TextView;\n\nimport com.lguipeng.notes.BuildConfig;\nimport com.lguipeng.notes.R;\nimport com.lguipeng.notes.adpater.MaterialSimpleListAdapter;\nimport com.lguipeng.notes.model.MaterialSimpleListItem;\nimport com.lguipeng.notes.module.DataModule;\nimport com.lguipeng.notes.utils.SnackbarUtils;\nimport com.lguipeng.notes.utils.TimeUtils;\nimport com.lguipeng.notes.utils.WXUtils;\nimport com.tencent.mm.sdk.modelmsg.SendMessageToWX;\nimport com.tencent.mm.sdk.modelmsg.WXMediaMessage;\nimport com.tencent.mm.sdk.modelmsg.WXWebpageObject;\nimport com.tencent.mm.sdk.openapi.IWXAPI;\nimport com.tencent.mm.sdk.openapi.WXAPIFactory;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport butterknife.InjectView;\nimport butterknife.OnClick;\n\n/**\n * Created by lgp on 2015/5/25.\n */\npublic class AboutActivity extends BaseActivity implements View.OnClickListener{\n    @InjectView(R.id.toolbar)\n    Toolbar toolbar;\n    @InjectView(R.id.version_text)\n    TextView versionTextView;\n    @InjectView(R.id.blog_btn)\n    Button blogButton;\n    @InjectView(R.id.project_home_btn)\n    Button projectHomeButton;\n    private int clickCount = 0;\n    private long lastClickTime = 0;\n    private final static String WEIBO_PACKAGENAME = \"com.sina.weibo\";\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        initVersionText();\n        blogButton.setOnClickListener(this);\n        projectHomeButton.setOnClickListener(this);\n    }\n\n    @Override\n    protected int getLayoutView() {\n        return R.layout.activity_about;\n    }\n\n    @Override\n    protected List<Object> getModules() {\n        return Arrays.<Object>asList(new DataModule());\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()){\n            case R.id.blog_btn:\n                startViewAction(BuildConfig.BLOG_URL);\n                break;\n            case R.id.project_home_btn:\n                startViewAction(BuildConfig.PROJECT_URL);\n                break;\n            default:\n                break;\n        }\n    }\n\n    @Override\n    protected void initToolbar(){\n        super.initToolbar(toolbar);\n        toolbar.setTitle(R.string.about);\n\n    }\n\n    @OnClick(R.id.version_text)\n    void versionClick(View view){\n        if (clickCount < 3){\n            if (TimeUtils.getCurrentTimeInLong() - lastClickTime < 500 || lastClickTime <= 0){\n                clickCount ++;\n                if (clickCount >= 3){\n                    startViewAction(BuildConfig.ABOUT_APP_URL);\n                    clickCount = 0;\n                    lastClickTime = 0;\n                    return;\n                }\n            }else {\n                clickCount = 0;\n                lastClickTime = 0;\n                return;\n            }\n            lastClickTime = TimeUtils.getCurrentTimeInLong();\n        }\n    }\n\n    private void initVersionText(){\n        versionTextView.setText(\"v\" + getVersion(this));\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_about, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()){\n            case R.id.share:\n               showShareDialog();\n                break;\n            default:\n                return super.onOptionsItemSelected(item);\n        }\n        return true;\n    }\n\n    private String getVersion(Context ctx){\n        try {\n            PackageManager pm = ctx.getPackageManager();\n            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);\n            return pi.versionName;\n        }catch (PackageManager.NameNotFoundException e)\n        {\n            e.printStackTrace();\n        }\n        return \"1.0.0\";\n    }\n\n    private void startViewAction(String uriStr){\n        try {\n            Uri uri = Uri.parse(uriStr);\n            Intent intent = new Intent(Intent.ACTION_VIEW, uri);\n            startActivity(intent);\n        } catch (ActivityNotFoundException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private void share(String packages, Uri uri){\n        Intent intent=new Intent(Intent.ACTION_SEND);\n        if (uri != null){\n            intent.setType(\"image/*\");\n            intent.putExtra(Intent.EXTRA_STREAM, uri);\n        }else {\n            intent.setType(\"text/plain\");\n        }\n        intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share));\n        intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_text, getString(R.string.download_url), BuildConfig.APP_DOWNLOAD_URL));\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        if (!TextUtils.isEmpty(packages))\n            intent.setPackage(packages);\n        startActivity(Intent.createChooser(intent, getString(R.string.share)));\n    }\n\n    private byte[] getLogoBitmapArray(){\n        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);\n        return WXUtils.bmpToByteArray(bitmap, false);\n    }\n\n    private void shareToWeChat(int scene){\n        IWXAPI api = WXAPIFactory.createWXAPI(this, BuildConfig.WECHAT_ID, true);\n        if (!api.isWXAppInstalled()){\n            SnackbarUtils.show(this, R.string.not_install_app);\n        }\n        api.registerApp(BuildConfig.WECHAT_ID);\n        WXWebpageObject object = new WXWebpageObject();\n        object.webpageUrl = \"http://www.wandoujia.com/apps/com.lguipeng.notes\";\n        WXMediaMessage msg = new WXMediaMessage(object);\n        msg.mediaObject = object;\n        msg.thumbData = getLogoBitmapArray();\n        msg.title = getString(R.string.app_desc);\n        msg.description = getString(R.string.share_text, \"\", \"\");\n        SendMessageToWX.Req request = new SendMessageToWX.Req();\n        request.message = msg;\n        request.scene = scene;\n        api.sendReq(request);\n        api.unregisterApp();\n    }\n\n    private void shareToWeChatTimeline(){\n        shareToWeChat(SendMessageToWX.Req.WXSceneTimeline);\n    }\n\n    private void shareToWeChatSession(){\n        shareToWeChat(SendMessageToWX.Req.WXSceneSession);\n    }\n\n    private void shareToWeChatFavorite(){\n        shareToWeChat(SendMessageToWX.Req.WXSceneFavorite);\n    }\n\n    private void shareToWeibo(){\n        if (isInstallApplication(WEIBO_PACKAGENAME)){\n            share(WEIBO_PACKAGENAME, null);\n        }else {\n            SnackbarUtils.show(this, R.string.not_install_app);\n        }\n    }\n\n    private boolean isInstallApplication(String packageName){\n        try {\n            PackageManager pm = this.getPackageManager();\n            pm.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);\n            return true;\n        } catch (PackageManager.NameNotFoundException e) {\n            return false;\n        }\n    }\n\n    private void showShareDialog(){\n        AlertDialog.Builder builder = generateDialogBuilder();\n        builder.setTitle(getString(R.string.share));\n        final MaterialSimpleListAdapter adapter = new MaterialSimpleListAdapter(this);\n        String[] array = getResources().getStringArray(R.array.share_dialog_text);\n        adapter.add(new MaterialSimpleListItem.Builder(this)\n                .content(array[0])\n                .icon(R.drawable.ic_wx_logo)\n                .build());\n        adapter.add(new MaterialSimpleListItem.Builder(this)\n                .content(array[1])\n                .icon(R.drawable.ic_wx_moments)\n                .build());\n        adapter.add(new MaterialSimpleListItem.Builder(this)\n                .content(array[2])\n                .icon(R.drawable.ic_wx_collect)\n                .build());\n        adapter.add(new MaterialSimpleListItem.Builder(this)\n                .content(array[3])\n                .icon(R.drawable.ic_sina_logo)\n                .build());\n        adapter.add(new MaterialSimpleListItem.Builder(this)\n                .content(array[4])\n                .icon(R.drawable.ic_share_more)\n                .build());\n        builder.setAdapter(adapter, new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                switch (which){\n                    case 0:\n                        shareToWeChatSession();\n                        break;\n                    case 1:\n                        shareToWeChatTimeline();\n                        break;\n                    case 2:\n                        shareToWeChatFavorite();\n                        break;\n                    case 3:\n                        shareToWeibo();\n                        break;\n                    default:\n                        share(\"\", null);\n                }\n            }\n        });\n        builder.show();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/ui/BaseActivity.java",
    "content": "package com.lguipeng.notes.ui;\n\nimport android.annotation.TargetApi;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.support.v7.app.AlertDialog;\nimport android.support.v7.app.AppCompatActivity;\nimport android.support.v7.widget.Toolbar;\nimport android.util.TypedValue;\nimport android.view.MenuItem;\nimport android.view.WindowManager;\n\nimport com.lguipeng.notes.App;\nimport com.lguipeng.notes.R;\nimport com.lguipeng.notes.utils.PreferenceUtils;\nimport com.lguipeng.notes.utils.ThemeUtils;\nimport com.readystatesoftware.systembartint.SystemBarTintManager;\n\nimport java.util.List;\n\nimport butterknife.ButterKnife;\nimport dagger.ObjectGraph;\n\n/**\n * Created by lgp on 2015/5/24.\n */\npublic abstract class BaseActivity extends AppCompatActivity {\n\n    private ObjectGraph activityGraph;\n\n    protected PreferenceUtils preferenceUtils;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        preferenceUtils = PreferenceUtils.getInstance(this);\n        initTheme();\n        super.onCreate(savedInstanceState);\n        initWindow();\n        activityGraph = ((App) getApplication()).createScopedGraph(getModules().toArray());\n        activityGraph.inject(this);\n        setContentView(getLayoutView());\n        ButterKnife.inject(this);\n        initToolbar();\n    }\n\n    private void initTheme(){\n        ThemeUtils.Theme theme = getCurrentTheme();\n        ThemeUtils.changTheme(this, theme);\n    }\n\n    protected int getColor(int res){\n        if (res <= 0)\n            throw new IllegalArgumentException(\"resource id can not be less 0\");\n        return getResources().getColor(res);\n    }\n\n    @TargetApi(19)\n    private void initWindow(){\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){\n            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);\n            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);\n            SystemBarTintManager tintManager = new SystemBarTintManager(this);\n            tintManager.setStatusBarTintColor(getStatusBarColor());\n            tintManager.setStatusBarTintEnabled(true);\n        }\n    }\n\n    protected void initToolbar(Toolbar toolbar){\n        if (toolbar == null)\n            return;\n        toolbar.setBackgroundColor(getColorPrimary());\n        toolbar.setTitle(R.string.app_name);\n        toolbar.setTitleTextColor(getColor(R.color.action_bar_title_color));\n        toolbar.collapseActionView();\n        setSupportActionBar(toolbar);\n        if (getSupportActionBar() != null){\n            getSupportActionBar().setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha);\n            getSupportActionBar().setDisplayHomeAsUpEnabled(true);\n        }\n    }\n\n    public int getStatusBarColor(){\n        return getColorPrimary();\n    }\n\n    public int getColorPrimary(){\n        TypedValue typedValue = new  TypedValue();\n        getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);\n        return typedValue.data;\n    }\n\n    public int getDarkColorPrimary(){\n        TypedValue typedValue = new  TypedValue();\n        getTheme().resolveAttribute(R.attr.colorPrimaryDark, typedValue, true);\n        return typedValue.data;\n    }\n\n    protected AlertDialog.Builder generateDialogBuilder(){\n        ThemeUtils.Theme theme = getCurrentTheme();\n        AlertDialog.Builder builder;\n        int style = R.style.RedDialogTheme;\n        switch (theme){\n            case BROWN:\n                style = R.style.BrownDialogTheme;\n                break;\n            case BLUE:\n                style = R.style.BlueDialogTheme;\n                break;\n            case BLUE_GREY:\n                style = R.style.BlueGreyDialogTheme;\n                break;\n            case YELLOW:\n                style = R.style.YellowDialogTheme;\n                break;\n            case DEEP_PURPLE:\n                style = R.style.DeepPurpleDialogTheme;\n                break;\n            case PINK:\n                style = R.style.PinkDialogTheme;\n                break;\n            case GREEN:\n                style = R.style.GreenDialogTheme;\n                break;\n            default:\n                break;\n        }\n        builder = new AlertDialog.Builder(this, style);\n        return builder;\n    }\n\n    protected ThemeUtils.Theme getCurrentTheme(){\n        int value = preferenceUtils.getIntParam(getString(R.string.change_theme_key), 0);\n        return ThemeUtils.Theme.mapValueToTheme(value);\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        activityGraph = null;\n    }\n\n    /**\n     * 增加了默认的返回finish事件\n     */\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        int id = item.getItemId();\n        switch (id) {\n            case android.R.id.home:\n                finish();\n                return true;\n            default:\n                return super.onOptionsItemSelected(item);\n        }\n        \n    }\n\n    protected abstract int getLayoutView();\n\n    protected abstract List<Object> getModules();\n\n    protected abstract void initToolbar();\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/ui/EditNoteTypeActivity.java",
    "content": "package com.lguipeng.notes.ui;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.support.v7.widget.Toolbar;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.inputmethod.InputMethodManager;\nimport android.widget.EditText;\nimport android.widget.LinearLayout;\n\nimport com.lguipeng.notes.R;\nimport com.lguipeng.notes.model.NoteType;\nimport com.lguipeng.notes.module.DataModule;\nimport com.lguipeng.notes.utils.JsonUtils;\nimport com.lguipeng.notes.utils.NoteConfig;\nimport com.lguipeng.notes.utils.PreferenceUtils;\nimport com.rengwuxian.materialedittext.MaterialEditText;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport butterknife.InjectView;\nimport de.greenrobot.event.EventBus;\n\n/**\n * Created by lgp on 2015/6/2.\n */\npublic class EditNoteTypeActivity extends BaseActivity{\n    @InjectView(R.id.toolbar)\n    Toolbar toolbar;\n\n    @InjectView(R.id.edit_root_view)\n    LinearLayout editRootView;\n\n    private MaterialEditText[] editTexts = new MaterialEditText[NoteType.ALL_COUNT - 1];\n\n    private MenuItem doneMenuItem;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        initEditTextView();\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_note, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(Menu menu) {\n        doneMenuItem = menu.getItem(0);\n        doneMenuItem.setVisible(false);\n        return super.onPrepareOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()){\n            case R.id.done:\n                hideKeyBoard(editTexts[0]);\n                NoteType type = new NoteType();\n                for (MaterialEditText view : editTexts){\n                    type.addType(view.getText().toString());\n                }\n\n                type.addType(getString(R.string.recycle_bin));\n                String json = JsonUtils.jsonNoteType(type);\n                preferenceUtils.saveParam(PreferenceUtils.NOTE_TYPE_KEY, json);\n                EventBus.getDefault().post(NoteConfig.NOTE_TYPE_UPDATE_EVENT);\n                finish();\n                return true;\n            default:\n                return super.onOptionsItemSelected(item);\n        }\n    }\n\n    @Override\n    protected int getLayoutView() {\n        return R.layout.activity_edit_note_type;\n    }\n\n    @Override\n    protected List<Object> getModules() {\n        return Arrays.<Object>asList(new DataModule());\n    }\n\n    @Override\n    protected void initToolbar(){\n        super.initToolbar(toolbar);\n        toolbar.setTitle(R.string.edit);\n    }\n\n    private void initEditTextView(){\n        String json = preferenceUtils.getStringParam(PreferenceUtils.NOTE_TYPE_KEY);\n        List<String> lists = JsonUtils.parseNoteType(json);\n        if (lists == null)\n            return;\n        for (int i=0; i< editTexts.length; i++){\n            MaterialEditText view = (MaterialEditText)getLayoutInflater().inflate(R.layout.edit_layout, null);\n            view.addTextChangedListener(new SimpleTextWatcher());\n            if (i < lists.size()){\n                view.setText(lists.get(i));\n                view.setSelection(lists.get(i).length());\n            }\n            editRootView.addView(view);\n            editTexts[i] = view;\n        }\n    }\n\n    class SimpleTextWatcher implements TextWatcher {\n\n        @Override\n        public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n\n        }\n\n        @Override\n        public void onTextChanged(CharSequence s, int start, int before, int count) {\n            if (doneMenuItem == null)\n                return;\n            boolean allFill = true;\n            for (MaterialEditText view : editTexts){\n                if (TextUtils.isEmpty(view.getText().toString()))\n                    allFill = false;\n            }\n            if (allFill){\n                doneMenuItem.setVisible(true);\n            }else {\n                doneMenuItem.setVisible(false);\n            }\n        }\n\n        @Override\n        public void afterTextChanged(Editable s) {\n\n        }\n    }\n\n    private void hideKeyBoard(EditText editText){\n        InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);\n        inputMethodManager.hideSoftInputFromWindow(editText.getWindowToken(), 0);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/ui/MainActivity.java",
    "content": "package com.lguipeng.notes.ui;\n\nimport android.app.SearchManager;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.res.Configuration;\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.support.v4.view.MenuItemCompat;\nimport android.support.v4.widget.DrawerLayout;\nimport android.support.v4.widget.SwipeRefreshLayout;\nimport android.support.v7.app.ActionBarDrawerToggle;\nimport android.support.v7.app.AlertDialog;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.PopupMenu;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.SearchView;\nimport android.support.v7.widget.StaggeredGridLayoutManager;\nimport android.support.v7.widget.Toolbar;\nimport android.text.TextUtils;\nimport android.view.Gravity;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.Button;\nimport android.widget.ListView;\n\nimport com.lguipeng.notes.R;\nimport com.lguipeng.notes.adpater.BaseRecyclerViewAdapter;\nimport com.lguipeng.notes.adpater.DrawerListAdapter;\nimport com.lguipeng.notes.adpater.NotesAdapter;\nimport com.lguipeng.notes.adpater.SimpleListAdapter;\nimport com.lguipeng.notes.listener.bmob.FindListenerImpl;\nimport com.lguipeng.notes.listener.bmob.SaveListenerImpl;\nimport com.lguipeng.notes.listener.bmob.UpdateListenerImpl;\nimport com.lguipeng.notes.model.CloudNote;\nimport com.lguipeng.notes.model.Note;\nimport com.lguipeng.notes.model.NoteOperateLog;\nimport com.lguipeng.notes.model.NoteType;\nimport com.lguipeng.notes.module.DataModule;\nimport com.lguipeng.notes.utils.AccountUtils;\nimport com.lguipeng.notes.utils.JsonUtils;\nimport com.lguipeng.notes.utils.NoteConfig;\nimport com.lguipeng.notes.utils.PreferenceUtils;\nimport com.lguipeng.notes.utils.SnackbarUtils;\nimport com.melnykov.fab.FloatingActionButton;\nimport com.melnykov.fab.ScrollDirectionListener;\nimport com.pnikosis.materialishprogress.ProgressWheel;\n\nimport net.tsz.afinal.FinalDb;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport butterknife.InjectView;\nimport butterknife.OnClick;\nimport cn.bmob.v3.BmobQuery;\nimport de.greenrobot.event.EventBus;\n\n/**\n * Created by lgp on 2015/5/24.\n */\npublic class MainActivity extends BaseActivity implements SwipeRefreshLayout.OnRefreshListener{\n\n    @InjectView(R.id.toolbar)\n    Toolbar toolbar;\n\n    @InjectView(R.id.refresher)\n    SwipeRefreshLayout refreshLayout;\n\n    @InjectView(R.id.recyclerView)\n    RecyclerView recyclerView;\n\n    @InjectView(R.id.drawer_layout)\n    DrawerLayout mDrawerLayout;\n\n    @InjectView(R.id.edit_note_type)\n    Button editNoteTypeButton;\n\n    @InjectView(R.id.left_drawer_listview)\n    ListView mDrawerMenuListView;\n\n    @InjectView(R.id.left_drawer)\n    View drawerRootView;\n\n    @InjectView(R.id.fab)\n    FloatingActionButton fab;\n\n    @InjectView(R.id.progress_wheel)\n    ProgressWheel progressWheel;\n\n    @Inject\n    FinalDb finalDb;\n\n    private ActionBarDrawerToggle mDrawerToggle;\n\n    private SearchView searchView;\n\n    private NotesAdapter recyclerAdapter;\n\n    private int mCurrentNoteType;\n\n    private boolean rightHandOn = false;\n\n    private boolean cardLayout = true;\n\n    private boolean hasUpdateNote = false;\n\n    private boolean hasEditClick = false;\n\n    private  List<String> noteTypelist;\n\n    private boolean hasSyncing = false;\n\n    private final String  CURRENT_NOTE_TYPE_KEY = \"CURRENT_NOTE_TYPE_KEY\";\n\n    private final String  PROGRESS_WHEEL_KEY = \"PROGRESS_WHEEL_KEY\";\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if (savedInstanceState != null){\n            mCurrentNoteType = savedInstanceState.getInt(CURRENT_NOTE_TYPE_KEY);\n            progressWheel.onRestoreInstanceState(savedInstanceState.getParcelable(PROGRESS_WHEEL_KEY));\n        }\n        initToolbar();\n        initDrawerView();\n        initRecyclerView();\n        EventBus.getDefault().register(this);\n    }\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        super.onSaveInstanceState(outState);\n        outState.putInt(CURRENT_NOTE_TYPE_KEY, mCurrentNoteType);\n        Parcelable parcelable = progressWheel.onSaveInstanceState();\n        outState.putParcelable(PROGRESS_WHEEL_KEY, parcelable);\n    }\n\n    @Override\n    public void onStart() {\n        super.onStart();\n        if (rightHandOn != preferenceUtils.getBooleanParam(getString(R.string.right_hand_mode_key))){\n            rightHandOn = !rightHandOn;\n            if (rightHandOn){\n                setMenuListViewGravity(Gravity.END);\n            }else{\n                setMenuListViewGravity(Gravity.START);\n            }\n        }\n\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (hasUpdateNote){\n            changeToSelectNoteType(mCurrentNoteType);\n            hasUpdateNote = false;\n        }\n        if (cardLayout != preferenceUtils.getBooleanParam(getString(R.string.card_note_item_layout_key), true)){\n            changeItemLayout(!cardLayout);\n        }\n    }\n\n    @Override\n    public void onStop() {\n        super.onStop();\n    }\n\n    @Override\n    public void onDestroy() {\n        EventBus.getDefault().unregister(this);\n        super.onDestroy();\n    }\n\n    public void onEvent(Integer event){\n        switch (event){\n            case NoteConfig.NOTE_UPDATE_EVENT:\n                hasUpdateNote = true;\n                break;\n            case NoteConfig.NOTE_TYPE_UPDATE_EVENT:\n                initDrawerListView();\n                break;\n            case NoteConfig.CHANGE_THEME_EVENT:\n                this.recreate();\n                break;\n        }\n    }\n\n    @Override\n    protected int getLayoutView() {\n        return R.layout.activity_main;\n    }\n\n    @Override\n    protected List<Object> getModules() {\n        return Arrays.<Object>asList(new DataModule());\n    }\n\n    @Override\n    public void onConfigurationChanged(Configuration newConfig) {\n        super.onConfigurationChanged(newConfig);\n        mDrawerToggle.onConfigurationChanged(newConfig);\n    }\n\n    @Override\n    public void onPostCreate(Bundle savedInstanceState) {\n        super.onPostCreate(savedInstanceState);\n        mDrawerToggle.syncState();\n        if (toolbar != null){\n            toolbar.setNavigationOnClickListener(new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    openOrCloseDrawer();\n                }\n            });\n        }\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_main, menu);\n        SearchManager searchManager =\n                (SearchManager) getSystemService(Context.SEARCH_SERVICE);\n        MenuItem searchItem = menu.findItem(R.id.action_search);\n        //searchItem.expandActionView();\n        searchView = (SearchView) MenuItemCompat.getActionView(searchItem);\n        ComponentName componentName = getComponentName();\n\n        searchView.setSearchableInfo(\n                searchManager.getSearchableInfo(componentName));\n        searchView.setQueryHint(getString(R.string.search_note));\n        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {\n            @Override\n            public boolean onQueryTextSubmit(String s) {\n                return true;\n            }\n\n            @Override\n            public boolean onQueryTextChange(String s) {\n                recyclerAdapter.getFilter().filter(s);\n                return true;\n            }\n        });\n        MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {\n            @Override\n            public boolean onMenuItemActionExpand(MenuItem item) {\n                recyclerAdapter.setUpFactor();\n                refreshLayout.setEnabled(false);\n                return true;\n            }\n\n            @Override\n            public boolean onMenuItemActionCollapse(MenuItem item) {\n                refreshLayout.setEnabled(true);\n                return true;\n            }\n        });\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        if(mDrawerToggle.onOptionsItemSelected(item)) {\n            return true;\n        }\n        Intent intent;\n        switch (item.getItemId()){\n            case R.id.setting:\n                intent = new Intent(MainActivity.this, SettingActivity.class);\n                startActivity(intent);\n                return true;\n            case R.id.sync:\n                sync();\n                return true;\n            case R.id.about:\n                intent = new Intent(MainActivity.this, AboutActivity.class);\n                startActivity(intent);\n                return true;\n            default:\n                return super.onOptionsItemSelected(item);\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (keyCode == KeyEvent.KEYCODE_BACK && mDrawerLayout.isDrawerOpen(drawerRootView)){\n            mDrawerLayout.closeDrawer(drawerRootView);\n            return true;\n        }\n        moveTaskToBack(true);\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    protected void initToolbar(){\n        super.initToolbar(toolbar);\n    }\n\n    private void initDrawerListView(){\n        String json = preferenceUtils.getStringParam(PreferenceUtils.NOTE_TYPE_KEY);\n        if (!TextUtils.isEmpty(json)){\n            noteTypelist = JsonUtils.parseNoteType(json);\n        }else{\n            noteTypelist = Arrays.asList(getResources().getStringArray(R.array.drawer_content));\n            NoteType type = new NoteType();\n            type.setTypes(noteTypelist);\n            String text = JsonUtils.jsonNoteType(type);\n            preferenceUtils.saveParam(PreferenceUtils.NOTE_TYPE_KEY, text);\n        }\n\n        SimpleListAdapter adapter = new DrawerListAdapter(this, noteTypelist);\n        mDrawerMenuListView.setAdapter(adapter);\n        mDrawerMenuListView.setItemChecked(mCurrentNoteType, true);\n        toolbar.setTitle(noteTypelist.get(mCurrentNoteType));\n    }\n\n    private void initDrawerView() {\n        initDrawerListView();\n        mDrawerMenuListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            @Override\n            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n                mDrawerMenuListView.setItemChecked(position, true);\n                openOrCloseDrawer();\n                mCurrentNoteType = position;\n                changeToSelectNoteType(mCurrentNoteType);\n                if (mCurrentNoteType == NoteConfig.NOTE_TRASH_TYPE) {\n                    fab.hide();\n                    fab.setVisibility(View.INVISIBLE);\n                } else {\n                    fab.setVisibility(View.VISIBLE);\n                    fab.show();\n                }\n            }\n        });\n\n        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, 0, 0){\n            @Override\n            public void onDrawerOpened(View drawerView) {\n                super.onDrawerOpened(drawerView);\n                invalidateOptionsMenu();\n                toolbar.setTitle(R.string.app_name);\n            }\n\n            @Override\n            public void onDrawerClosed(View drawerView) {\n                super.onDrawerClosed(drawerView);\n                invalidateOptionsMenu();\n                toolbar.setTitle(noteTypelist.get(mCurrentNoteType));\n                if (hasEditClick){\n                    Intent intent = new Intent(MainActivity.this, EditNoteTypeActivity.class);\n                    startActivity(intent);\n                    hasEditClick = false;\n                }\n            }\n        };\n        mDrawerToggle.setDrawerIndicatorEnabled(true);\n        mDrawerLayout.setDrawerListener(mDrawerToggle);\n        mDrawerLayout.setScrimColor(getColor(R.color.drawer_scrim_color));\n        rightHandOn = preferenceUtils.getBooleanParam(getString(R.string.right_hand_mode_key));\n        if (rightHandOn){\n            setMenuListViewGravity(Gravity.END);\n        }\n    }\n\n\n\n    private void initRecyclerView(){\n        showProgressWheel(true);\n        initItemLayout();\n        recyclerView.setHasFixedSize(true);\n        recyclerAdapter = new NotesAdapter(initItemData(mCurrentNoteType), this);\n        recyclerAdapter.setOnInViewClickListener(R.id.notes_item_root,\n                new BaseRecyclerViewAdapter.onInternalClickListenerImpl<Note>() {\n                    @Override\n                    public void OnClickListener(View parentV, View v, Integer position, Note values) {\n                        super.OnClickListener(parentV, v, position, values);\n                        if (mCurrentNoteType == NoteConfig.NOTE_TRASH_TYPE)\n                            return;\n                        startNoteActivity(NoteActivity.VIEW_NOTE_TYPE, values);\n                    }\n                });\n        recyclerAdapter.setOnInViewClickListener(R.id.note_more,\n                new BaseRecyclerViewAdapter.onInternalClickListenerImpl<Note>() {\n                    @Override\n                    public void OnClickListener(View parentV, View v, Integer position, Note values) {\n                        super.OnClickListener(parentV, v, position, values);\n                        showPopupMenu(v, values);\n                    }\n                });\n        recyclerAdapter.setFirstOnly(false);\n        recyclerAdapter.setDuration(300);\n        recyclerView.setAdapter(recyclerAdapter);\n        fab.attachToRecyclerView(recyclerView, new ScrollDirectionListener() {\n            @Override\n            public void onScrollDown() {\n                recyclerAdapter.setDownFactor();\n            }\n\n            @Override\n            public void onScrollUp() {\n                recyclerAdapter.setUpFactor();\n            }\n        });\n        showProgressWheel(false);\n        refreshLayout.setColorSchemeColors(getColorPrimary());\n        refreshLayout.setOnRefreshListener(this);\n    }\n\n    @OnClick(R.id.fab)\n    public void newNote(View view){\n        Note note = new Note();\n        note.setType(mCurrentNoteType);\n        startNoteActivity(NoteActivity.CREATE_NOTE_TYPE, note);\n    }\n\n    @OnClick(R.id.edit_note_type)\n    public void editNoteType(View view){\n        hasEditClick = true;\n        openOrCloseDrawer();\n    }\n\n\n    @Override\n    public void onRefresh() {\n        sync();\n    }\n\n    private void changeToSelectNoteType(int type){\n        showProgressWheel(true);\n        recyclerAdapter.setList(initItemData(type));\n        showProgressWheel(false);\n    }\n\n    private void openDrawer() {\n        if (!mDrawerLayout.isDrawerOpen(drawerRootView)) {\n            mDrawerLayout.openDrawer(drawerRootView);\n        }\n    }\n\n    private void closeDrawer() {\n        if (mDrawerLayout.isDrawerOpen(drawerRootView)) {\n            mDrawerLayout.closeDrawer(drawerRootView);\n        }\n    }\n\n    private void openOrCloseDrawer() {\n        if (mDrawerLayout.isDrawerOpen(drawerRootView)) {\n            mDrawerLayout.closeDrawer(drawerRootView);\n        } else {\n            mDrawerLayout.openDrawer(drawerRootView);\n        }\n    }\n\n    private void showPopupMenu(View view, final Note note) {\n        PopupMenu popup = new PopupMenu(this, view);\n        //Inflating the Popup using xml file\n        String move = getString(R.string.move_to);\n        if (mCurrentNoteType == NoteConfig.NOTE_TRASH_TYPE){\n            for (int i=0; i< noteTypelist.size()-1; i++){\n                popup.getMenu().add(Menu.NONE, i, Menu.NONE, move + noteTypelist.get(i));\n            }\n            popup.getMenu().add(Menu.NONE, noteTypelist.size()-1, Menu.NONE, getString(R.string.delete_forever));\n            popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {\n                @Override\n                public boolean onMenuItemClick(MenuItem item) {\n                    int id = item.getItemId();\n                    if (id < noteTypelist.size() - 1) {\n                        note.setType(id);\n                        finalDb.update(note);\n                        changeToSelectNoteType(mCurrentNoteType);\n                    } else {\n                        showDeleteForeverDialog(note);\n                    }\n                    return true;\n                }\n            });\n\n        } else {\n            popup.getMenuInflater()\n                    .inflate(R.menu.menu_notes_more, popup.getMenu());\n            popup.setOnMenuItemClickListener(\n                    new PopupMenu.OnMenuItemClickListener() {\n                        @Override\n                        public boolean onMenuItemClick(MenuItem item) {\n                            switch (item.getItemId()) {\n                                case R.id.delete_forever:\n                                    showDeleteForeverDialog(note);\n                                    break;\n                                case R.id.edit:\n                                    startNoteActivity(NoteActivity.EDIT_NOTE_TYPE, note);\n                                    break;\n                                case R.id.move_to_trash:\n                                    note.setType(NoteConfig.NOTE_TRASH_TYPE);\n                                    finalDb.update(note);\n                                    changeToSelectNoteType(mCurrentNoteType);\n                                    break;\n                                default:\n                                    break;\n                            }\n                            return true;\n                        }\n                    });\n        }\n        popup.show(); //showing popup menu\n    }\n\n    private void showDeleteForeverDialog(final Note note){\n        AlertDialog.Builder builder = generateDialogBuilder();\n        builder.setTitle(R.string.delete_forever_message);\n        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                switch (which){\n                    case DialogInterface.BUTTON_POSITIVE:\n                        for (NoteOperateLog log : note.getLogs().getList()){\n                            finalDb.delete(log);\n                        }\n                        finalDb.delete(note);\n                        changeToSelectNoteType(mCurrentNoteType);\n                        break;\n                    case DialogInterface.BUTTON_NEGATIVE:\n                        break;\n                    default:\n                        break;\n                }\n            }\n        };\n        builder.setPositiveButton(R.string.sure, listener);\n        builder.setNegativeButton(R.string.cancel, listener);\n        builder.show();\n    }\n\n    private void startNoteActivity(int oprType, Note value){\n        Intent intent = new Intent(this, NoteActivity.class);\n        Bundle bundle = new Bundle();\n        bundle.putInt(NoteActivity.OPERATE_NOTE_TYPE_KEY, oprType);\n        EventBus.getDefault().postSticky(value);\n        intent.putExtras(bundle);\n        startActivity(intent);\n    }\n\n    private void setMenuListViewGravity(int gravity){\n        DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) drawerRootView.getLayoutParams();\n        params.gravity = gravity;\n        drawerRootView.setLayoutParams(params);\n    }\n\n    private List<Note> initItemData(int noteType) {\n        List<Note> itemList = null;\n        switch (noteType){\n            case NoteConfig.NOTE_STUDY_TYPE:\n            case NoteConfig.NOTE_WORK_TYPE:\n            case NoteConfig.NOTE_OTHER_TYPE:\n            case NoteConfig.NOTE_TRASH_TYPE:\n                itemList = finalDb.findAllByWhere(Note.class, \"type = \" + noteType, \"lastOprTime\", true);\n                break;\n            default:\n                break;\n        }\n        return itemList;\n    }\n\n    private void showProgressWheel(boolean visible){\n        progressWheel.setBarColor(getColorPrimary());\n        if (visible){\n            if (!progressWheel.isSpinning())\n                progressWheel.spin();\n        }else{\n            progressWheel.postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    if (progressWheel.isSpinning()) {\n                        progressWheel.stopSpinning();\n                    }\n                }\n            }, 500);\n        }\n    }\n\n    private void syncNotes(final String account){\n        new Thread(){\n            @Override\n            public void run() {\n                BmobQuery<CloudNote> query = new BmobQuery<>();\n                query.addWhereEqualTo(\"email\", account);\n                query.findObjects(MainActivity.this, new FindListenerImpl<CloudNote>(){\n                    CloudNote cloudNote;\n                    @Override\n                    public void onSuccess(List<CloudNote> notes) {\n                        List<Note> list = finalDb.findAll(Note.class);\n                        if (notes != null && notes.size() >= 1){\n                            cloudNote = notes.get(0);\n                            long localVersion = preferenceUtils.getLongParam(account);\n                            if (cloudNote.getVersion() > localVersion){\n                                //pull notes\n                                preferenceUtils.saveParam(PreferenceUtils.NOTE_TYPE_KEY, cloudNote.getNoteType());\n                                for (String string : cloudNote.getNoteList()) {\n                                    Note note = JsonUtils.parseNote(string);\n                                    if (note == null)\n                                        continue;\n                                    finalDb.saveBindId(note);\n                                    NoteOperateLog log = new NoteOperateLog();\n                                    log.setTime(note.getLastOprTime());\n                                    log.setType(NoteConfig.NOTE_CREATE_OPR);\n                                    log.setNote(note);\n                                    finalDb.save(log);\n                                }\n                                preferenceUtils.saveParam(account, cloudNote.getVersion());\n                                runOnUiThread(new Runnable() {\n                                    @Override\n                                    public void run() {\n                                        initDrawerListView();\n                                        changeToSelectNoteType(mCurrentNoteType);\n                                        onSyncSuccess();\n                                    }\n                                });\n                                return;\n                            }else {\n                                //upload notes\n                                cloudNote.setVersion(++localVersion);\n                            }\n                        }else {\n                            cloudNote = new CloudNote();\n                            cloudNote.setEmail(account);\n                            cloudNote.setVersion(1);\n\n                        }\n                        cloudNote.clearNotes();\n                        for (Note note : list){\n                            cloudNote.addNote(note);\n                        }\n                        String json = preferenceUtils.getStringParam(PreferenceUtils.NOTE_TYPE_KEY);\n                        cloudNote.setNoteType(json);\n                        if (TextUtils.isEmpty(cloudNote.getObjectId())){\n                            cloudNote.save(MainActivity.this, new SaveListenerImpl() {\n                                @Override\n                                public void onSuccess() {\n                                    preferenceUtils.saveParam(account, cloudNote.getVersion());\n                                    onSyncSuccess();\n                                }\n\n                                @Override\n                                public void onFailure(int i, String s) {\n                                    super.onFailure(i, s);\n                                    onSyncFail();\n                                }\n                            });\n                        }else{\n                            cloudNote.update(MainActivity.this, new UpdateListenerImpl() {\n                                @Override\n                                public void onSuccess() {\n                                    preferenceUtils.saveParam(account, cloudNote.getVersion());\n                                    onSyncSuccess();\n                                }\n\n                                @Override\n                                public void onFailure(int i, String s) {\n                                    super.onFailure(i, s);\n                                    onSyncFail();\n                                }\n                            });\n                        }\n                    }\n\n                    @Override\n                    public void onError(int i, String s) {\n                        super.onError(i, s);\n                        onSyncFail();\n                    }\n                });\n            }\n        }.start();\n    }\n\n    private void sync(){\n        if (hasSyncing)\n            return;\n        String account = preferenceUtils.getStringParam(getString(R.string.sync_account_key));\n        if (TextUtils.isEmpty(account)){\n            AccountUtils.findValidAccount(getApplicationContext(), new AccountUtils.AccountFinderListener() {\n                @Override\n                protected void onNone() {\n                    if (refreshLayout.isRefreshing()){\n                        refreshLayout.setRefreshing(false);\n                    }\n                    SnackbarUtils.show(MainActivity.this, R.string.no_account_tip);\n                }\n\n                @Override\n                protected void onOne(String account) {\n                    preferenceUtils.saveParam(getString(R.string.sync_account_key), account);\n                    hasSyncing = true;\n                    syncNotes(account);\n                }\n\n                @Override\n                protected void onMore(List<String> accountItems) {\n                    if (refreshLayout.isRefreshing()){\n                        refreshLayout.setRefreshing(false);\n                    }\n                    SnackbarUtils.show(MainActivity.this, R.string.no_account_tip);\n                }\n            });\n\n        }else {\n            if (!refreshLayout.isRefreshing()){\n                refreshLayout.setRefreshing(true);\n            }\n            hasSyncing = true;\n            syncNotes(account);\n        }\n    }\n\n    private void onSyncSuccess(){\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                hasSyncing = false;\n                refreshLayout.setRefreshing(false);\n                SnackbarUtils.show(MainActivity.this, R.string.sync_success);\n            }\n        });\n    }\n\n    private void onSyncFail(){\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                hasSyncing = false;\n                refreshLayout.setRefreshing(false);\n                SnackbarUtils.show(MainActivity.this, R.string.sync_fail);\n            }\n        });\n    }\n\n    private void changeItemLayout(boolean flow){\n        cardLayout = flow;\n        if (!flow){\n            recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));\n        }else {\n            recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL));\n        }\n    }\n\n    private void initItemLayout(){\n        if (preferenceUtils.getBooleanParam(getString(R.string.card_note_item_layout_key), true)){\n            cardLayout = true;\n            recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL));\n        }else {\n            cardLayout = false;\n            recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/ui/NoteActivity.java",
    "content": "package com.lguipeng.notes.ui;\n\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AlertDialog;\nimport android.support.v7.widget.Toolbar;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.inputmethod.InputMethodManager;\nimport android.widget.EditText;\nimport android.widget.TextView;\n\nimport com.lguipeng.notes.R;\nimport com.lguipeng.notes.model.Note;\nimport com.lguipeng.notes.model.NoteOperateLog;\nimport com.lguipeng.notes.module.DataModule;\nimport com.lguipeng.notes.utils.NoteConfig;\nimport com.lguipeng.notes.utils.TimeUtils;\nimport com.rengwuxian.materialedittext.MaterialEditText;\n\nimport net.tsz.afinal.FinalDb;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport butterknife.InjectView;\nimport de.greenrobot.event.EventBus;\n\n/**\n * Created by lgp on 2015/5/25.\n */\npublic class NoteActivity extends BaseActivity{\n    @InjectView(R.id.toolbar)\n    Toolbar toolbar;\n\n    @InjectView(R.id.label_edit_text)\n    MaterialEditText labelEditText;\n\n    @InjectView(R.id.content_edit_text)\n    MaterialEditText contentEditText;\n\n    @InjectView(R.id.opr_time_line_text)\n    TextView oprTimeLineTextView;\n\n    @Inject\n    FinalDb finalDb;\n\n    private MenuItem doneMenuItem;\n\n    private int operateNoteType = 0;\n\n    private Note note;\n\n    public final static String OPERATE_NOTE_TYPE_KEY = \"OPERATE_NOTE_TYPE_KEY\";\n\n    public final static int VIEW_NOTE_TYPE = 0x00;\n    public final static int EDIT_NOTE_TYPE = 0x01;\n    public final static int CREATE_NOTE_TYPE = 0x02;\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        parseIntent(getIntent());\n        EventBus.getDefault().registerSticky(this);\n    }\n\n    @Override\n    public void onDestroy() {\n        EventBus.getDefault().unregister(this);\n        super.onDestroy();\n    }\n\n    @Override\n    protected int getLayoutView() {\n        return R.layout.activity_note;\n    }\n\n    @Override\n    protected List<Object> getModules() {\n        return Arrays.<Object>asList(new DataModule());\n    }\n\n    public void onEventMainThread(Note note) {\n        this.note = note;\n        initToolbar();\n        initEditText();\n        initTextView();\n    }\n\n    private void parseIntent(Intent intent){\n        if (intent != null && intent.getExtras() != null){\n            operateNoteType = intent.getExtras().getInt(OPERATE_NOTE_TYPE_KEY, 0);\n        }\n    }\n\n    @Override\n    protected void initToolbar(){\n        super.initToolbar(toolbar);\n        toolbar.setTitle(R.string.view_note);\n        switch (operateNoteType){\n            case CREATE_NOTE_TYPE:\n                toolbar.setTitle(R.string.new_note);\n                break;\n            case EDIT_NOTE_TYPE:\n                toolbar.setTitle(R.string.edit_note);\n                break;\n            case VIEW_NOTE_TYPE:\n                toolbar.setTitle(R.string.view_note);\n                break;\n            default:\n                break;\n        }\n    }\n\n    private void initEditText(){\n        switch (operateNoteType){\n            case EDIT_NOTE_TYPE:\n                labelEditText.requestFocus();\n                labelEditText.setText(note.getLabel());\n                contentEditText.setText(note.getContent());\n                labelEditText.setSelection(note.getLabel().length());\n                contentEditText.setSelection(note.getContent().length());\n                break;\n            case VIEW_NOTE_TYPE:\n                labelEditText.setText(note.getLabel());\n                contentEditText.setText(note.getContent());\n                labelEditText.setOnFocusChangeListener(new SimpleOnFocusChangeListener());\n                contentEditText.setOnFocusChangeListener(new SimpleOnFocusChangeListener());\n                break;\n            default:\n                labelEditText.requestFocus();\n                break;\n        }\n        labelEditText.addTextChangedListener(new SimpleTextWatcher());\n        contentEditText.addTextChangedListener(new SimpleTextWatcher());\n    }\n\n    private void initTextView(){\n        boolean all = preferenceUtils.getBooleanParam(getString(R.string.show_note_history_log_key));\n        oprTimeLineTextView.setText(getOprTimeLineText(note, all));\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_note, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(Menu menu) {\n        doneMenuItem = menu.getItem(0);\n        doneMenuItem.setVisible(false);\n        return super.onPrepareOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()){\n            case R.id.done:\n                saveNote();\n                return true;\n            case android.R.id.home:\n                if (doneMenuItem.isVisible()){\n                    showNotSaveNoteDialog();\n                    return true;\n                }\n                finish();\n            default:\n                return super.onOptionsItemSelected(item);\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (keyCode == KeyEvent.KEYCODE_BACK){\n            if (doneMenuItem != null && doneMenuItem.isVisible()){\n                showNotSaveNoteDialog();\n                return true;\n            }\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    private void showNotSaveNoteDialog(){\n        hideKeyBoard(labelEditText);\n        AlertDialog.Builder builder = generateDialogBuilder();\n        builder.setTitle(R.string.not_save_note_leave_tip);\n        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                switch (which){\n                    case DialogInterface.BUTTON_POSITIVE:\n                        saveNote();\n                        break;\n                    case DialogInterface.BUTTON_NEGATIVE:\n                        NoteActivity.this.finish();\n                        break;\n                    default:\n                        break;\n                }\n            }\n        };\n        builder.setPositiveButton(R.string.sure, listener);\n        builder.setNegativeButton(R.string.cancel, listener);\n        builder.show();\n    }\n\n    private void saveNote(){\n        hideKeyBoard(labelEditText);\n        note.setLabel(labelEditText.getText().toString());\n        note.setContent(contentEditText.getText().toString());\n        note.setLastOprTime(TimeUtils.getCurrentTimeInLong());\n\n        NoteOperateLog log = new NoteOperateLog();\n        log.setTime(TimeUtils.getCurrentTimeInLong());\n        switch (operateNoteType){\n            case CREATE_NOTE_TYPE:\n                finalDb.saveBindId(note);\n                log.setType(NoteConfig.NOTE_CREATE_OPR);\n                log.setNote(note);\n                finalDb.save(log);\n                break;\n            default:\n                finalDb.update(note);\n                log.setType(NoteConfig.NOTE_EDIT_OPR);\n                log.setNote(note);\n                finalDb.save(log);\n                break;\n        }\n        EventBus.getDefault().post(NoteConfig.NOTE_UPDATE_EVENT);\n        finish();\n    }\n\n    class SimpleTextWatcher implements TextWatcher {\n\n        @Override\n        public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n\n        }\n\n        @Override\n        public void onTextChanged(CharSequence s, int start, int before, int count) {\n            if (doneMenuItem == null)\n                return;\n            String labelSrc = labelEditText.getText().toString();\n            String contentSrc = contentEditText.getText().toString();\n            String label = labelSrc.replaceAll(\"\\\\s*|\\t|\\r|\\n\", \"\");\n            String content = contentSrc.replaceAll(\"\\\\s*|\\t|\\r|\\n\", \"\");\n            if (!TextUtils.isEmpty(label) && !TextUtils.isEmpty(content)){\n                if (TextUtils.equals(labelSrc, note.getLabel()) && TextUtils.equals(contentSrc, note.getContent())){\n                    doneMenuItem.setVisible(false);\n                    return;\n                }\n                doneMenuItem.setVisible(true);\n            }else{\n                doneMenuItem.setVisible(false);\n            }\n        }\n\n        @Override\n        public void afterTextChanged(Editable s) {\n\n        }\n    }\n\n    class SimpleOnFocusChangeListener implements View.OnFocusChangeListener {\n        @Override\n        public void onFocusChange(View v, boolean hasFocus) {\n            if (hasFocus && toolbar != null){\n                toolbar.setTitle(R.string.edit_note);\n            }\n        }\n    }\n\n    private String getOprTimeLineText(Note note, boolean all){\n        if (note == null || note.getLogs() == null)\n            return \"\";\n        String create = getString(R.string.create);\n        String edit = getString(R.string.edit);\n        StringBuilder sb = new StringBuilder();\n        if (note.getLogs().getList().size() <= 0){\n            return \"\";\n        }\n        NoteOperateLog log;\n        List<NoteOperateLog> logs = note.getLogs().getList();\n        int size = logs.size();\n        if (!all){\n            log = logs.get(size - 1);\n            if (log.getType() == NoteConfig.NOTE_CREATE_OPR){\n                sb.append(getString(R.string.note_log_text, create, TimeUtils.getTime(log.getTime())));\n            }else{\n                sb.append(getString(R.string.note_log_text, edit, TimeUtils.getTime(log.getTime())));\n            }\n            return sb.toString();\n        }\n        for (int i=size-1; i>=0; i--){\n            log = logs.get(i);\n            if (log.getType() == NoteConfig.NOTE_CREATE_OPR){\n                sb.append(getString(R.string.note_log_text, create, TimeUtils.getTime(log.getTime())));\n            }else{\n                sb.append(getString(R.string.note_log_text, edit, TimeUtils.getTime(log.getTime())));\n            }\n            sb.append(\"\\n\");\n        }\n        return sb.toString();\n    }\n\n    private void hideKeyBoard(EditText editText){\n        InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);\n        inputMethodManager.hideSoftInputFromWindow(editText.getWindowToken(), 0);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/ui/PayActivity.java",
    "content": "package com.lguipeng.notes.ui;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.Toolbar;\n\nimport com.lguipeng.notes.R;\nimport com.lguipeng.notes.module.DataModule;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport butterknife.InjectView;\n\n/**\n * Created by lgp on 2015/6/1.\n */\npublic class PayActivity extends BaseActivity{\n    @InjectView(R.id.toolbar)\n    Toolbar toolbar;\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    protected int getLayoutView() {\n        return R.layout.activity_pay;\n    }\n\n    @Override\n    protected List<Object> getModules() {\n        return Arrays.<Object>asList(new DataModule());\n    }\n\n    @Override\n    protected void initToolbar(){\n        super.initToolbar(toolbar);\n        toolbar.setTitle(R.string.pay_for_me);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/ui/SettingActivity.java",
    "content": "package com.lguipeng.notes.ui;\n\nimport android.os.Bundle;\nimport android.support.v7.widget.Toolbar;\n\nimport com.lguipeng.notes.R;\nimport com.lguipeng.notes.module.DataModule;\nimport com.lguipeng.notes.ui.fragments.SettingFragment;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport butterknife.InjectView;\n\n/**\n * Created by lgp on 2015/5/24.\n */\npublic class SettingActivity extends BaseActivity{\n    @InjectView(R.id.toolbar)\n    Toolbar toolbar;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        init();\n    }\n\n    @Override\n    protected int getLayoutView() {\n        return R.layout.activity_setting;\n    }\n\n    @Override\n    protected List<Object> getModules() {\n        return Arrays.<Object>asList(new DataModule());\n    }\n\n    @Override\n    protected void initToolbar(){\n        super.initToolbar(toolbar);\n        toolbar.setTitle(R.string.setting);\n    }\n\n    private void init(){\n        SettingFragment settingFragment = SettingFragment.newInstance();\n        getFragmentManager().beginTransaction().replace(R.id.fragment_content, settingFragment).commit();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/ui/fragments/BaseFragment.java",
    "content": "package com.lguipeng.notes.ui.fragments;\n\nimport android.os.Bundle;\nimport android.preference.PreferenceFragment;\nimport android.support.v7.app.AlertDialog;\n\nimport com.lguipeng.notes.App;\nimport com.lguipeng.notes.R;\nimport com.lguipeng.notes.ui.BaseActivity;\nimport com.lguipeng.notes.utils.PreferenceUtils;\nimport com.lguipeng.notes.utils.ThemeUtils;\n\nimport java.util.List;\n\nimport dagger.ObjectGraph;\n\n/**\n * Created by lgp on 2015/5/26.\n */\npublic abstract class BaseFragment extends PreferenceFragment {\n\n    private ObjectGraph activityGraph;\n    protected BaseActivity activity;\n    protected PreferenceUtils preferenceUtils;\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        activityGraph = ((App) getActivity().getApplication()).createScopedGraph(getModules().toArray());\n        activityGraph.inject(this);\n    }\n\n    @Override\n    public void onActivityCreated(Bundle savedInstanceState) {\n        super.onActivityCreated(savedInstanceState);\n        if (getActivity() != null && getActivity() instanceof BaseActivity){\n            activity = (BaseActivity)getActivity();\n        }\n        preferenceUtils = PreferenceUtils.getInstance(getActivity());\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        activityGraph = null;\n    }\n\n    protected AlertDialog.Builder generateDialogBuilder(){\n        ThemeUtils.Theme theme = getCurrentTheme();\n        AlertDialog.Builder builder;\n        switch (theme){\n            case BROWN:\n                builder = new AlertDialog.Builder(getActivity(), R.style.BrownDialogTheme);\n                break;\n            case BLUE:\n                builder = new AlertDialog.Builder(getActivity(), R.style.BlueDialogTheme);\n                break;\n            case BLUE_GREY:\n                builder = new AlertDialog.Builder(getActivity(), R.style.BlueGreyDialogTheme);\n                break;\n            default:\n                builder = new AlertDialog.Builder(getActivity(), R.style.RedDialogTheme);\n                break;\n        }\n        return builder;\n    }\n\n    protected ThemeUtils.Theme getCurrentTheme(){\n        int value = preferenceUtils.getIntParam(getString(R.string.change_theme_key), 0);\n        return ThemeUtils.Theme.mapValueToTheme(value);\n    }\n\n    protected abstract List<Object> getModules();\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/ui/fragments/SettingFragment.java",
    "content": "package com.lguipeng.notes.ui.fragments;\n\nimport android.content.ActivityNotFoundException;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.preference.PreferenceScreen;\nimport android.support.v7.app.AlertDialog;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.GridView;\n\nimport com.jenzz.materialpreference.CheckBoxPreference;\nimport com.jenzz.materialpreference.Preference;\nimport com.jenzz.materialpreference.SwitchPreference;\nimport com.lguipeng.notes.R;\nimport com.lguipeng.notes.adpater.ColorsListAdapter;\nimport com.lguipeng.notes.module.DataModule;\nimport com.lguipeng.notes.ui.PayActivity;\nimport com.lguipeng.notes.utils.AccountUtils;\nimport com.lguipeng.notes.utils.NoteConfig;\nimport com.lguipeng.notes.utils.PreferenceUtils;\nimport com.lguipeng.notes.utils.ThemeUtils;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport de.greenrobot.event.EventBus;\n\n/**\n * Created by lgp on 2015/5/26.\n */\npublic class SettingFragment extends BaseFragment{\n\n    public static final String PREFERENCE_FILE_NAME = \"note.settings\";\n\n    private CheckBoxPreference showNoteHistoryLogCheckBox;\n\n    private SwitchPreference rightHandModeSwitch;\n\n    private Preference feedbackPreference;\n\n    private Preference payMePreference;\n\n    private Preference giveFavorPreference;\n\n    private Preference accountPreference;\n\n    private boolean showNoteHistoryLog;\n\n    private boolean rightHandMode;\n\n    private boolean cardLayout;\n\n    private  List<String> accountItems = new ArrayList<>();\n\n    private PreferenceUtils preferenceUtils;\n\n    public static SettingFragment newInstance(){\n        SettingFragment fragment = new SettingFragment();\n        return fragment;\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        preferenceUtils = PreferenceUtils.getInstance(getActivity());\n        addPreferencesFromResource(R.xml.prefs);\n        getPreferenceManager().setSharedPreferencesName(PREFERENCE_FILE_NAME);\n        showNoteHistoryLog = preferenceUtils.getBooleanParam(getString(R.string.show_note_history_log_key));\n        rightHandMode = preferenceUtils.getBooleanParam(getString(R.string.right_hand_mode_key));\n        showNoteHistoryLogCheckBox = (CheckBoxPreference)findPreference(getString(R.string.show_note_history_log_key));\n        showNoteHistoryLogCheckBox.setChecked(showNoteHistoryLog);\n        rightHandModeSwitch = (SwitchPreference)findPreference(getString(R.string.right_hand_mode_key));\n        rightHandModeSwitch.setChecked(rightHandMode);\n        cardLayout = preferenceUtils.getBooleanParam(getString(R.string.card_note_item_layout_key), true);\n        CheckBoxPreference cardLayoutPreference = (CheckBoxPreference)findPreference(getString(R.string.card_note_item_layout_key));\n        cardLayoutPreference.setChecked(cardLayout);\n        feedbackPreference = (Preference)findPreference(getString(R.string.advice_feedback_key));\n        accountPreference = (Preference)findPreference(getString(R.string.sync_account_key));\n        payMePreference = (Preference)findPreference(getString(R.string.pay_for_me_key));\n        giveFavorPreference = (Preference)findPreference(getString(R.string.give_favor_key));\n        initFeedbackPreference();\n        initAccountPreference();\n    }\n\n    @Override\n    public void onViewCreated(View view, Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        View listView = view.findViewById(android.R.id.list);\n        listView.setHorizontalScrollBarEnabled(false);\n        listView.setVerticalScrollBarEnabled(false);\n    }\n\n    public SettingFragment() {\n        super();\n    }\n\n    @Override\n    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,  android.preference.Preference preference) {\n        if (preference == null)\n            return super.onPreferenceTreeClick(preferenceScreen, preference);\n        String key = preference.getKey();\n        if (TextUtils.equals(key, getString(R.string.right_hand_mode_key))){\n            rightHandMode = !rightHandMode;\n            preferenceUtils.saveParam(getString(R.string.right_hand_mode_key), rightHandMode);\n        }\n\n        if (TextUtils.equals(key, getString(R.string.card_note_item_layout_key))){\n            cardLayout = !cardLayout;\n            preferenceUtils.saveParam(getString(R.string.card_note_item_layout_key), cardLayout);\n        }\n\n        if (TextUtils.equals(key, getString(R.string.show_note_history_log_key))){\n            showNoteHistoryLog = !showNoteHistoryLog;\n            preferenceUtils.saveParam(getString(R.string.show_note_history_log_key), showNoteHistoryLog);\n        }\n\n        if (TextUtils.equals(key, getString(R.string.change_theme_key))){\n           showThemeChooseDialog();\n        }\n\n        if (TextUtils.equals(key, getString(R.string.pay_for_me_key))){\n            Intent intent = new Intent(getActivity(), PayActivity.class);\n            startActivity(intent);\n        }\n\n        if (TextUtils.equals(key, getString(R.string.give_favor_key))){\n            giveFavor();\n        }\n        return super.onPreferenceTreeClick(preferenceScreen, preference);\n    }\n\n    @Override\n    protected List<Object> getModules() {\n        return Arrays.<Object>asList(new DataModule());\n    }\n\n    private void initFeedbackPreference(){\n        Uri uri = Uri.parse(\"mailto:lgpszu@163.com\");\n        final Intent intent = new Intent(Intent.ACTION_SENDTO, uri);\n        PackageManager pm = getActivity().getPackageManager();\n        List<ResolveInfo> infos = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);\n        if (infos == null || infos.size() <= 0){\n            feedbackPreference.setSummary(getString(R.string.no_email_app_tip));\n            return;\n        }\n        feedbackPreference.setOnPreferenceClickListener(new android.preference.Preference.OnPreferenceClickListener() {\n            @Override\n            public boolean onPreferenceClick(android.preference.Preference preference) {\n                startActivity(intent);\n                return true;\n            }\n        });\n\n    }\n\n    private void initAccountPreference(){\n        AccountUtils.findValidAccount(getActivity(), new AccountUtils.AccountFinderListener() {\n            @Override\n            protected void onNone() {\n                accountPreference.setSummary(getString(R.string.no_account_tip));\n            }\n\n            @Override\n            protected void onOne(String account) {\n                accountPreference.setSummary(account);\n                preferenceUtils.saveParam(getString(R.string.sync_account_key), account);\n            }\n\n            @Override\n            protected void onMore(List<String> items) {\n                SettingFragment.this.accountItems = items;\n                String account = preferenceUtils.getStringParam(getString(R.string.sync_account_key));\n                if (!isHasAccountSave()) {\n                    accountPreference.setSummary(getString(R.string.multi_account_choose_tip));\n                } else {\n                    accountPreference.setSummary(account);\n                }\n\n                accountPreference.setOnPreferenceClickListener(new android.preference.Preference.OnPreferenceClickListener() {\n                    @Override\n                    public boolean onPreferenceClick(android.preference.Preference preference) {\n                        showAccountChooseDialog(accountItems.toArray(new String[accountItems.size()]));\n                        return true;\n                    }\n                });\n            }\n        });\n    }\n\n    private void showThemeChooseDialog(){\n        AlertDialog.Builder builder = generateDialogBuilder();\n        builder.setTitle(R.string.change_theme);\n        Integer[] res = new Integer[]{R.drawable.red_round, R.drawable.brown_round, R.drawable.blue_round,\n                R.drawable.blue_grey_round, R.drawable.yellow_round, R.drawable.deep_purple_round,\n                R.drawable.pink_round, R.drawable.green_round};\n        List<Integer> list = Arrays.asList(res);\n        ColorsListAdapter adapter = new ColorsListAdapter(getActivity(), list);\n        adapter.setCheckItem(getCurrentTheme().getIntValue());\n        GridView gridView = (GridView)LayoutInflater.from(getActivity()).inflate(R.layout.colors_panel_layout, null);\n        gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);\n        gridView.setCacheColorHint(0);\n        gridView.setAdapter(adapter);\n        builder.setView(gridView);\n        final AlertDialog dialog = builder.show();\n        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            @Override\n            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n                dialog.dismiss();\n                int value = getCurrentTheme().getIntValue();\n                if (value != position){\n                    preferenceUtils.saveParam(getString(R.string.change_theme_key), position);\n                    changeTheme(ThemeUtils.Theme.mapValueToTheme(position));\n                }\n            }\n        });\n    }\n\n    private void showAccountChooseDialog(final CharSequence[] text){\n        AlertDialog.Builder builder = generateDialogBuilder();\n        builder.setTitle(R.string.choose_account);\n        builder.setItems(text, new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                accountPreference.setSummary(text[which]);\n                String account = preferenceUtils.getStringParam(getString(R.string.sync_account_key));\n                if (TextUtils.equals(account, text[which]))\n                    return;\n                preferenceUtils.saveParam(getString(R.string.sync_account_key), text[which].toString());\n            }\n        });\n        builder.show();\n    }\n\n    private void giveFavor(){\n        try{\n            Uri uri = Uri.parse(\"market://details?id=\"+ getActivity().getPackageName());\n            Intent intent = new Intent(Intent.ACTION_VIEW, uri);\n            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            startActivity(intent);\n        }catch(ActivityNotFoundException e){\n            e.printStackTrace();\n        }\n    }\n\n    private void changeTheme(ThemeUtils.Theme theme){\n        if (activity == null)\n            return;\n        //ThemeUtils.changTheme(activity, theme);\n        //activity.recreate();\n        EventBus.getDefault().post(NoteConfig.CHANGE_THEME_EVENT);\n        activity.finish();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/utils/AccountUtils.java",
    "content": "package com.lguipeng.notes.utils;\n\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.util.Patterns;\n\nimport com.lguipeng.notes.R;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\n/**\n * Created by lgp on 2015/5/29.\n */\npublic class AccountUtils {\n\n    private static final String EMAIL_TYPE = \"com.android.email\";\n\n    public static void findValidAccount(Context context, AccountFinderListener listener){\n        if (listener == null)\n            return;\n        String accountString = PreferenceUtils.getInstance(context).getStringParam(context.getString(R.string.sync_account_key));\n        if (!TextUtils.isEmpty(accountString)){\n            listener.setHasAccountSave(true);\n        }\n        Pattern emailPattern = Patterns.EMAIL_ADDRESS;\n        Account[] accounts = AccountManager.get(context.getApplicationContext()).getAccounts();\n        List<String> accountItems = new ArrayList<>();\n        for (Account account : accounts) {\n            if (emailPattern.matcher(account.name).matches() && TextUtils.equals(EMAIL_TYPE, account.type)) {\n                accountItems.add(account.name);\n            }\n        }\n        if (accountItems.size() <= 0){\n            if (listener.isHasAccountSave()){\n                listener.onOne(accountString);\n                return;\n            }\n            listener.onNone();\n        }\n        if (accountItems.size() == 1){\n            if (listener.isHasAccountSave()){\n                listener.onOne(accountString);\n                return;\n            }\n            listener.onOne(accountItems.get(0));\n        }\n\n        if (accountItems.size() > 1){\n           listener.onMore(accountItems);\n        }\n    }\n\n    public static abstract class AccountFinderListener{\n        private boolean hasAccountSave = false;\n        protected abstract void onNone();\n        protected abstract void onOne(String account);\n        protected abstract void onMore(List<String> accountItems);\n\n        public boolean isHasAccountSave() {\n            return hasAccountSave;\n        }\n\n        public void setHasAccountSave(boolean hasAccountSave) {\n            this.hasAccountSave = hasAccountSave;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/utils/JsonUtils.java",
    "content": "package com.lguipeng.notes.utils;\n\nimport android.text.TextUtils;\n\nimport com.alibaba.fastjson.JSON;\nimport com.lguipeng.notes.model.Note;\nimport com.lguipeng.notes.model.NoteType;\n\nimport java.util.List;\n\n/**\n * Created by lgp on 2015/5/28.\n */\npublic class JsonUtils {\n\n    public static <T> String json(T note){\n        if (note == null)\n            return \"\";\n        try {\n            return JSON.toJSONString(note);\n        }catch (Exception e){\n            e.printStackTrace();\n            return \"\";\n        }\n    }\n\n    public static <T> T parse(String json, Class<T> clazz){\n        if (TextUtils.isEmpty(json))\n            return null;\n        try {\n            return JSON.parseObject(json, clazz);\n        }catch (Exception e){\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    public static Note parseNote(String json){\n        return parse(json, Note.class);\n    }\n\n    public static String jsonNote(Note note){\n        return json(note);\n    }\n\n    public static List<String> parseNoteType(String json){\n        NoteType type = parse(json, NoteType.class);\n        if (type == null)\n            return null;\n        return type.getTypes();\n    }\n\n    public static String jsonNoteType(NoteType type){\n        return json(type);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/utils/NoteConfig.java",
    "content": "package com.lguipeng.notes.utils;\n\n/**\n * Created by lgp on 2015/5/25.\n */\npublic class NoteConfig {\n\n    public final static int NOTE_CREATE_OPR = 0x00;\n    public final static int NOTE_EDIT_OPR = 0x01;\n\n    public final static int NOTE_STUDY_TYPE = 0x00;\n    public final static int NOTE_WORK_TYPE = 0x01;\n    public final static int NOTE_OTHER_TYPE = 0x02;\n    public final static int NOTE_TRASH_TYPE = 0x03;\n\n    public final static int NOTE_UPDATE_EVENT = 0x00;\n    public final static int NOTE_TYPE_UPDATE_EVENT = 0x01;\n    public final static int CHANGE_THEME_EVENT = 0x02;\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/utils/NotesLog.java",
    "content": "/***\n This is free and unencumbered software released into the public domain.\n Anyone is free to copy, modify, publish, use, compile, sell, or\n distribute this software, either in source code form or as a compiled\n binary, for any purpose, commercial or non-commercial, and by any\n means.\n For more information, please refer to <http://unlicense.org/>\n */\n\npackage com.lguipeng.notes.utils;\n\nimport android.util.Log;\n\nimport com.lguipeng.notes.BuildConfig;\n\n/**\n * @date 21.06.2012\n * @author Mustafa Ferhan Akman\n *\n * Create a simple and more understandable Android logs. \n * */\n\npublic class NotesLog{\n\n    static String className;\n    static String methodName;\n    static int lineNumber;\n\n    private NotesLog(){\n        /* Protect from instantiations */\n    }\n\n    public static boolean isDebuggable() {\n        return BuildConfig.DEBUG;\n    }\n\n    private static String createLog( String log ) {\n\n        StringBuffer buffer = new StringBuffer();\n        buffer.append(\"[\");\n        buffer.append(methodName);\n        buffer.append(\":\");\n        buffer.append(lineNumber);\n        buffer.append(\"]\");\n        buffer.append(log);\n\n        return buffer.toString();\n    }\n\n    private static void getMethodNames(StackTraceElement[] sElements){\n        className = sElements[1].getFileName();\n        methodName = sElements[1].getMethodName();\n        lineNumber = sElements[1].getLineNumber();\n    }\n\n    public static void e(String message){\n        if (!isDebuggable())\n            return;\n\n        // Throwable instance must be created before any methods\n        getMethodNames(new Throwable().getStackTrace());\n        Log.e(className, createLog(message));\n    }\n\n    public static void i(String message){\n        if (!isDebuggable())\n            return;\n\n        getMethodNames(new Throwable().getStackTrace());\n        Log.i(className, createLog(message));\n    }\n\n    public static void d(String message){\n        if (!isDebuggable())\n            return;\n\n        getMethodNames(new Throwable().getStackTrace());\n        Log.d(className, createLog(message));\n    }\n\n    public static void d(){\n        d(\"\");\n    }\n\n    public static void v(String message){\n        if (!isDebuggable())\n            return;\n\n        getMethodNames(new Throwable().getStackTrace());\n        Log.v(className, createLog(message));\n    }\n\n    public static void w(String message){\n        if (!isDebuggable())\n            return;\n\n        getMethodNames(new Throwable().getStackTrace());\n        Log.w(className, createLog(message));\n    }\n\n    public static void wtf(String message){\n        if (!isDebuggable())\n            return;\n\n        getMethodNames(new Throwable().getStackTrace());\n        Log.wtf(className, createLog(message));\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/utils/PreferenceUtils.java",
    "content": "package com.lguipeng.notes.utils;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\nimport com.lguipeng.notes.ui.fragments.SettingFragment;\n\n/**\n * Created by lgp on 2014/10/30.\n */\npublic class PreferenceUtils{\n\n    private SharedPreferences sharedPreferences;\n\n    private SharedPreferences.Editor shareEditor;\n\n    private static PreferenceUtils preferenceUtils = null;\n\n    public static final String NOTE_TYPE_KEY = \"NOTE_TYPE_KEY\";\n\n    private PreferenceUtils(Context context){\n        sharedPreferences = context.getSharedPreferences(SettingFragment.PREFERENCE_FILE_NAME, Context.MODE_PRIVATE);\n        shareEditor = sharedPreferences.edit();\n    }\n\n    public static PreferenceUtils getInstance(Context context){\n        if (preferenceUtils == null) {\n            synchronized (PreferenceUtils.class) {\n                if (preferenceUtils == null) {\n                    preferenceUtils = new PreferenceUtils(context.getApplicationContext());\n                }\n            }\n        }\n        return preferenceUtils;\n    }\n\n    public String getStringParam(String key){\n        return getStringParam(key, \"\");\n    }\n\n    public String getStringParam(String key, String defaultString){\n        return sharedPreferences.getString(key, defaultString);\n    }\n\n    public void saveParam(String key, String value)\n    {\n        shareEditor.putString(key,value).commit();\n    }\n\n    public boolean getBooleanParam(String key){\n        return getBooleanParam(key, false);\n    }\n\n    public boolean getBooleanParam(String key, boolean defaultBool){\n        return sharedPreferences.getBoolean(key, defaultBool);\n    }\n\n    public void saveParam(String key, boolean value){\n        shareEditor.putBoolean(key, value).commit();\n    }\n\n    public int getIntParam(String key){\n        return getIntParam(key, 0);\n    }\n\n    public int getIntParam(String key, int defaultInt){\n        return sharedPreferences.getInt(key, defaultInt);\n    }\n\n    public void saveParam(String key, int value){\n        shareEditor.putInt(key, value).commit();\n    }\n\n    public long getLongParam(String key){\n        return getLongParam(key, 0);\n    }\n\n    public long getLongParam(String key, long defaultInt){\n        return sharedPreferences.getLong(key, defaultInt);\n    }\n\n    public void saveParam(String key, long value){\n        shareEditor.putLong(key, value).commit();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/utils/SnackbarUtils.java",
    "content": "package com.lguipeng.notes.utils;\n\nimport android.app.Activity;\nimport android.graphics.Color;\n\nimport com.lguipeng.notes.ui.BaseActivity;\nimport com.nispok.snackbar.Snackbar;\nimport com.nispok.snackbar.SnackbarManager;\n\n/**\n * Author: lgp\n * Date: 2014/12/31.\n */\npublic class SnackbarUtils {\n\n    public static void show(Activity activity, int message) {\n//        Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();\n//        Toast toast = new Toast(mContext);\n//        View view = LayoutInflater.from(mContext).inflate(R.layout.toast_layout, null, false);\n//        TextView textView = (TextView)view.findViewById(R.id.toast_text);\n//        textView.setText(message);\n//        toast.setView(view);\n//        toast.setDuration(Toast.LENGTH_SHORT);\n//        toast.show();\n        int color = Color.BLACK;\n        if (activity instanceof BaseActivity){\n            color = (((BaseActivity) activity)).getColorPrimary();\n        }\n        color = color & 0xddffffff;\n        SnackbarManager.show(\n                Snackbar.with(activity.getApplicationContext())\n                        .color(color)\n                        .duration((Snackbar.SnackbarDuration.LENGTH_SHORT.getDuration() / 2))\n                        .text(message), activity);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/utils/ThemeUtils.java",
    "content": "package com.lguipeng.notes.utils;\n\nimport android.app.Activity;\n\nimport com.lguipeng.notes.R;\n\n/**\n * Created by lgp on 2015/6/7.\n */\npublic class ThemeUtils {\n\n    public static void changTheme(Activity activity, Theme theme){\n        if (activity == null)\n            return;\n        int style = R.style.RedTheme;\n        switch (theme){\n            case BROWN:\n                style = R.style.BrownTheme;\n                break;\n            case BLUE:\n                style = R.style.BlueTheme;\n                break;\n            case BLUE_GREY:\n                style = R.style.BlueGreyTheme;\n                break;\n            case YELLOW:\n                style = R.style.YellowTheme;\n                break;\n            case DEEP_PURPLE:\n                style = R.style.DeepPurpleTheme;\n                break;\n            case PINK:\n                style = R.style.PinkTheme;\n                break;\n            case GREEN:\n                style = R.style.GreenTheme;\n                break;\n            default:\n                break;\n        }\n        activity.setTheme(style);\n    }\n\n    public enum Theme{\n        RED(0x00),\n        BROWN(0x01),\n        BLUE(0x02),\n        BLUE_GREY(0x03),\n        YELLOW(0x04),\n        DEEP_PURPLE(0x05),\n        PINK(0x06),\n        GREEN(0x07);\n\n        private int mValue;\n\n        Theme(int value){\n            this.mValue = value;\n        }\n\n        public static Theme mapValueToTheme(final int value) {\n            for (Theme theme : Theme.values()) {\n                if (value == theme.getIntValue()) {\n                    return theme;\n                }\n            }\n            // If run here, return default\n            return RED;\n        }\n\n        static Theme getDefault()\n        {\n            return RED;\n        }\n        public int getIntValue() {\n            return mValue;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/utils/TimeUtils.java",
    "content": "package com.lguipeng.notes.utils;\n\nimport android.content.Context;\n\nimport com.lguipeng.notes.R;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * Created by lgp on 2015/5/25.\n */\npublic class TimeUtils {\n    public static final long DAY_Millis = 24 * 60 * 60 * 1000;\n    public static final long MONTH_Millis = 30 * DAY_Millis;\n    public static final long YEAR_Millis = 365 * DAY_Millis;\n    public static final SimpleDateFormat DEFAULT_DATE_FORMAT = new SimpleDateFormat(\"yyyy.MM.dd    HH : mm\");\n    public static final SimpleDateFormat DATE_FORMAT_DATE_1    = new SimpleDateFormat(\" HH : mm \");\n\n    private TimeUtils() {\n        throw new AssertionError();\n    }\n\n    /**\n     * long time to string\n     *\n     * @param timeInMillis\n     * @param dateFormat\n     * @return\n     */\n    public static String getTime(long timeInMillis, SimpleDateFormat dateFormat) {\n        return dateFormat.format(new Date(timeInMillis));\n    }\n\n    /**\n     * long time to string, format is {@link #DEFAULT_DATE_FORMAT}\n     *\n     * @param timeInMillis\n     * @return\n     */\n    public static String getTime(long timeInMillis) {\n        return getTime(timeInMillis, DEFAULT_DATE_FORMAT);\n    }\n\n    @SuppressWarnings(\"Deprecated\")\n    public static String getConciseTime(long timeInMillis, long nowInMillis, Context context) {\n        if (context == null)\n            return \"\";\n        Date date = new Date(timeInMillis);\n        Date now = new Date(nowInMillis);\n\n        if (now.getYear() == date.getYear()) {\n            if (now.getMonth() == date.getMonth()) {\n                if (now.getDate() == date.getDate())\n                    return context.getString(R.string.today, getTime(timeInMillis, DATE_FORMAT_DATE_1));\n                else{\n                    return context.getString(R.string.before_day, now.getDate() - date.getDate());\n                }\n            }else {\n                return context.getString(R.string.before_month, now.getMonth() - date.getMonth());\n            }\n        }\n        return context.getString(R.string.before_year, now.getYear() - date.getYear());\n    }\n\n\n    public static String getConciseTime(long timeInMillis, Context context) {\n        return getConciseTime(timeInMillis, getCurrentTimeInLong(), context);\n    }\n    /**\n     * get current time in milliseconds\n     *\n     * @return\n     */\n    public static long getCurrentTimeInLong() {\n        return System.currentTimeMillis();\n    }\n\n    /**\n     * get current time in milliseconds, format is {@link #DEFAULT_DATE_FORMAT}\n     *\n     * @return\n     */\n    public static String getCurrentTimeInString() {\n        return getTime(getCurrentTimeInLong());\n    }\n\n    /**\n     * get current time in milliseconds\n     *\n     * @return\n     */\n    public static String getCurrentTimeInString(SimpleDateFormat dateFormat) {\n        return getTime(getCurrentTimeInLong(), dateFormat);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/utils/ViewHelper.java",
    "content": "package com.lguipeng.notes.utils;\n\nimport android.support.v4.view.ViewCompat;\nimport android.view.View;\n\n/**\n * Created by lgp on 2015/5/27.\n */\npublic class ViewHelper {\n    public static void clear(View v) {\n        ViewCompat.setAlpha(v, 1);\n        ViewCompat.setScaleY(v, 1);\n        ViewCompat.setScaleX(v, 1);\n        ViewCompat.setTranslationY(v, 0);\n        ViewCompat.setTranslationX(v, 0);\n        ViewCompat.setRotation(v, 0);\n        ViewCompat.setRotationY(v, 0);\n        ViewCompat.setRotationX(v, 0);\n        // @TODO https://code.google.com/p/android/issues/detail?id=80863\n//        ViewCompat.setPivotY(v, v.getMeasuredHeight() / 2);\n        v.setPivotY(v.getMeasuredHeight() / 2);\n        ViewCompat.setPivotX(v, v.getMeasuredWidth() / 2);\n        ViewCompat.animate(v).setInterpolator(null);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/utils/WXUtils.java",
    "content": "package com.lguipeng.notes.utils;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.CompressFormat;\nimport android.graphics.BitmapFactory;\n\nimport junit.framework.Assert;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.net.HttpURLConnection;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLConnection;\n\npublic class WXUtils {\n\t\n\tpublic static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {\n\t\tByteArrayOutputStream output = new ByteArrayOutputStream();\n\t\tbmp.compress(CompressFormat.PNG, 100, output);\n\t\tif (needRecycle) {\n\t\t\tbmp.recycle();\n\t\t}\n\t\t\n\t\tbyte[] result = output.toByteArray();\n\t\ttry {\n\t\t\toutput.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\treturn result;\n\t}\n\t\n\tpublic static byte[] getHtmlByteArray(final String url) {\n\t\t URL htmlUrl = null;     \n\t\t InputStream inStream = null;     \n\t\t try {         \n\t\t\t htmlUrl = new URL(url);         \n\t\t\t URLConnection connection = htmlUrl.openConnection();         \n\t\t\t HttpURLConnection httpConnection = (HttpURLConnection)connection;         \n\t\t\t int responseCode = httpConnection.getResponseCode();         \n\t\t\t if(responseCode == HttpURLConnection.HTTP_OK){             \n\t\t\t\t inStream = httpConnection.getInputStream();         \n\t\t\t  }     \n\t\t\t } catch (MalformedURLException e) {               \n\t\t\t\t e.printStackTrace();     \n\t\t\t } catch (IOException e) {              \n\t\t\t\te.printStackTrace();    \n\t\t  } \n\t\tbyte[] data = inputStreamToByte(inStream);\n\n\t\treturn data;\n\t}\n\t\n\tpublic static byte[] inputStreamToByte(InputStream is) {\n\t\ttry{\n\t\t\tByteArrayOutputStream bytestream = new ByteArrayOutputStream();\n\t\t\tint ch;\n\t\t\twhile ((ch = is.read()) != -1) {\n\t\t\t\tbytestream.write(ch);\n\t\t\t}\n\t\t\tbyte imgdata[] = bytestream.toByteArray();\n\t\t\tbytestream.close();\n\t\t\treturn imgdata;\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\treturn null;\n\t}\n\t\n\tpublic static byte[] readFromFile(String fileName, int offset, int len) {\n\t\tif (fileName == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tFile file = new File(fileName);\n\t\tif (!file.exists()) {\n\t\t\tNotesLog.i(\"readFromFile: file not found\");\n\t\t\treturn null;\n\t\t}\n\n\t\tif (len == -1) {\n\t\t\tlen = (int) file.length();\n\t\t}\n\n\t\tNotesLog.d(\"readFromFile : offset = \" + offset + \" len = \" + len + \" offset + len = \" + (offset + len));\n\n\t\tif(offset <0){\n\t\t\tNotesLog.e(\"readFromFile invalid offset:\" + offset);\n\t\t\treturn null;\n\t\t}\n\t\tif(len <=0 ){\n\t\t\tNotesLog.e(\"readFromFile invalid len:\" + len);\n\t\t\treturn null;\n\t\t}\n\t\tif(offset + len > (int) file.length()){\n\t\t\tNotesLog.e(\"readFromFile invalid file len:\" + file.length());\n\t\t\treturn null;\n\t\t}\n\n\t\tbyte[] b = null;\n\t\ttry {\n\t\t\tRandomAccessFile in = new RandomAccessFile(fileName, \"r\");\n\t\t\tb = new byte[len];\n\t\t\tin.seek(offset);\n\t\t\tin.readFully(b);\n\t\t\tin.close();\n\n\t\t} catch (Exception e) {\n\t\t\tNotesLog.e(\"readFromFile : errMsg = \" + e.getMessage());\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn b;\n\t}\n\t\n\tprivate static final int MAX_DECODE_PICTURE_SIZE = 1920 * 1440;\n\tpublic static Bitmap extractThumbNail(final String path, final int height, final int width, final boolean crop) {\n\t\tAssert.assertTrue(path != null && !path.equals(\"\") && height > 0 && width > 0);\n\n\t\tBitmapFactory.Options options = new BitmapFactory.Options();\n\n\t\ttry {\n\t\t\toptions.inJustDecodeBounds = true;\n\t\t\tBitmap tmp = BitmapFactory.decodeFile(path, options);\n\t\t\tif (tmp != null) {\n\t\t\t\ttmp.recycle();\n\t\t\t\ttmp = null;\n\t\t\t}\n\n\t\t\tNotesLog.d(\"extractThumbNail: round=\" + width + \"x\" + height + \", crop=\" + crop);\n\t\t\tfinal double beY = options.outHeight * 1.0 / height;\n\t\t\tfinal double beX = options.outWidth * 1.0 / width;\n\t\t\tNotesLog.d(\"extractThumbNail: extract beX = \" + beX + \", beY = \" + beY);\n\t\t\toptions.inSampleSize = (int) (crop ? (beY > beX ? beX : beY) : (beY < beX ? beX : beY));\n\t\t\tif (options.inSampleSize <= 1) {\n\t\t\t\toptions.inSampleSize = 1;\n\t\t\t}\n\n\t\t\t// NOTE: out of memory error\n\t\t\twhile (options.outHeight * options.outWidth / options.inSampleSize > MAX_DECODE_PICTURE_SIZE) {\n\t\t\t\toptions.inSampleSize++;\n\t\t\t}\n\n\t\t\tint newHeight = height;\n\t\t\tint newWidth = width;\n\t\t\tif (crop) {\n\t\t\t\tif (beY > beX) {\n\t\t\t\t\tnewHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth);\n\t\t\t\t} else {\n\t\t\t\t\tnewWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (beY < beX) {\n\t\t\t\t\tnewHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth);\n\t\t\t\t} else {\n\t\t\t\t\tnewWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toptions.inJustDecodeBounds = false;\n\n\t\t\tNotesLog.i(\"bitmap required size=\" + newWidth + \"x\" + newHeight + \", orig=\" + options.outWidth + \"x\" + options.outHeight + \", sample=\" + options.inSampleSize);\n\t\t\tBitmap bm = BitmapFactory.decodeFile(path, options);\n\t\t\tif (bm == null) {\n\t\t\t\tNotesLog.e(\"bitmap decode failed\");\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tNotesLog.i(\"bitmap decoded size=\" + bm.getWidth() + \"x\" + bm.getHeight());\n\t\t\tfinal Bitmap scale = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);\n\t\t\tif (scale != null) {\n\t\t\t\tbm.recycle();\n\t\t\t\tbm = scale;\n\t\t\t}\n\n\t\t\tif (crop) {\n\t\t\t\tfinal Bitmap cropped = Bitmap.createBitmap(bm, (bm.getWidth() - width) >> 1, (bm.getHeight() - height) >> 1, width, height);\n\t\t\t\tif (cropped == null) {\n\t\t\t\t\treturn bm;\n\t\t\t\t}\n\n\t\t\t\tbm.recycle();\n\t\t\t\tbm = cropped;\n\t\t\t\tNotesLog.i(\"bitmap croped size=\" + bm.getWidth() + \"x\" + bm.getHeight());\n\t\t\t}\n\t\t\treturn bm;\n\n\t\t} catch (final OutOfMemoryError e) {\n\t\t\tNotesLog.e(\"decode bitmap failed: \" + e.getMessage());\n\t\t\toptions = null;\n\t\t}\n\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "app/src/main/java/com/lguipeng/notes/view/FixedRecyclerView.java",
    "content": "package com.lguipeng.notes.view;\n\nimport android.content.Context;\nimport android.support.v7.widget.RecyclerView;\nimport android.util.AttributeSet;\n\n/**\n * Created by lgp on 2015/6/11.\n */\npublic class FixedRecyclerView extends RecyclerView {\n    public FixedRecyclerView(Context context) {\n        super(context);\n    }\n\n    public FixedRecyclerView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public FixedRecyclerView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n    }\n\n    @Override\n    public boolean canScrollVertically(int direction) {\n        // check if scrolling up\n        if (direction < 1) {\n            boolean original = super.canScrollVertically(direction);\n            return !original && getChildAt(0) != null && getChildAt(0).getTop() < 0 || original;\n        }\n        return super.canScrollVertically(direction);\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/drawable/activated_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_activated=\"true\" android:drawable=\"@drawable/abc_list_pressed_holo_dark\" />\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/abc_list_pressed_holo_dark\" />\n    <item android:state_long_pressable=\"true\" android:drawable=\"@drawable/abc_list_pressed_holo_dark\" />\n    <item  android:drawable=\"@android:color/transparent\" />\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/blue_grey_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"oval\">\n    <solid android:color=\"@color/blue_grey\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/blue_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"oval\">\n    <solid android:color=\"@color/blue\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/brown_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"oval\">\n    <solid android:color=\"@color/brown\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/deep_purple_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"oval\">\n    <solid android:color=\"@color/deep_purple\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/green_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"oval\">\n    <solid android:color=\"@color/green\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/pink_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"oval\">\n    <solid android:color=\"@color/pink\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/red_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"oval\">\n    <solid android:color=\"@color/red\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/selectable_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/abc_list_pressed_holo_dark\" />\n    <item  android:drawable=\"@android:color/transparent\" />\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/toolbar_shadow.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"rectangle\">\n    <gradient\n        android:startColor=\"@android:color/transparent\"\n        android:endColor=\"@color/light_grey\"\n        android:angle=\"90\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/white_button_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"rectangle\">\n    <corners android:radius=\"2dp\"/>\n    <solid android:color=\"@android:color/white\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/yellow_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"oval\">\n    <solid android:color=\"@color/yellow\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/layout/activity_about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:background=\"?attr/colorPrimary\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <include layout=\"@layout/toolbar_layout\" />\n    <ScrollView\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:id=\"@+id/scroll_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:fadingEdge=\"none\"\n        android:scrollbars=\"none\"\n        android:cacheColorHint=\"@android:color/transparent\"\n        android:scrollingCache=\"false\"\n        android:overScrollMode=\"never\">\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:background=\"?attr/colorPrimary\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_horizontal\"\n                android:layout_marginTop=\"120dp\"\n                android:textColor=\"@android:color/white\"\n                android:textSize=\"@dimen/abc_text_size_display_1_material\"\n                android:text=\"@string/app_name\"/>\n            <TextView\n                android:id=\"@+id/version_text\"\n                android:layout_gravity=\"center_horizontal\"\n                android:layout_marginTop=\"10dp\"\n                android:textColor=\"@android:color/white\"\n                android:textSize=\"@dimen/abc_text_size_medium_material\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"/>\n            <com.balysv.materialripple.MaterialRippleLayout\n                android:layout_marginTop=\"120dp\"\n                android:layout_marginLeft=\"30dp\"\n                android:layout_marginRight=\"30dp\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n                app:mrl_rippleOverlay=\"true\"\n                app:mrl_rippleColor=\"?attr/colorPrimary\">\n                <Button\n                    android:background=\"@drawable/white_button_background\"\n                    android:id=\"@+id/blog_btn\"\n                    android:textColor=\"?attr/colorPrimary\"\n                    android:text=\"@string/jianshu_blog\"\n                    android:textSize=\"@dimen/abc_text_size_button_material\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\" />\n            </com.balysv.materialripple.MaterialRippleLayout>\n\n            <com.balysv.materialripple.MaterialRippleLayout\n                android:layout_marginTop=\"14dp\"\n                android:layout_marginLeft=\"30dp\"\n                android:layout_marginRight=\"30dp\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n                app:mrl_rippleOverlay=\"true\"\n                app:mrl_rippleColor=\"?attr/colorPrimary\">\n                <Button\n                    android:background=\"@drawable/white_button_background\"\n                    android:id=\"@+id/project_home_btn\"\n                    android:textColor=\"?attr/colorPrimary\"\n                    android:text=\"@string/project_home\"\n                    android:textSize=\"@dimen/abc_text_size_button_material\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\" />\n            </com.balysv.materialripple.MaterialRippleLayout>\n            <TextView\n                android:layout_marginTop=\"20dp\"\n                android:textColor=\"#33ffffff\"\n                android:layout_gravity=\"center\"\n                android:text=\"@string/about_bottom_text\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n        </LinearLayout>\n    </ScrollView>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_edit_note_type.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <include layout=\"@layout/toolbar_layout\" />\n    <include layout=\"@layout/toolbar_shadow_layout\"/>\n    <ScrollView\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:id=\"@+id/scroll_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:fadingEdge=\"none\"\n        android:scrollbars=\"none\"\n        android:cacheColorHint=\"@android:color/transparent\"\n        android:scrollingCache=\"false\"\n        android:overScrollMode=\"never\">\n        <LinearLayout\n            android:id=\"@+id/edit_root_view\"\n            android:orientation=\"vertical\"\n            android:layout_marginLeft=\"25dp\"\n            android:layout_marginRight=\"25dp\"\n            android:layout_marginBottom=\"25dp\"\n            android:layout_marginTop=\"10dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n        </LinearLayout>\n    </ScrollView>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <include layout=\"@layout/toolbar_layout\" />\n    <android.support.v4.widget.DrawerLayout\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:id=\"@+id/drawer_layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <!--The main content view-->\n        <FrameLayout\n            xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            xmlns:fab=\"http://schemas.android.com/apk/res-auto\"\n            xmlns:wheel=\"http://schemas.android.com/apk/res-auto\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n            <android.support.v4.widget.SwipeRefreshLayout\n                android:id=\"@+id/refresher\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\">\n                <com.lguipeng.notes.view.FixedRecyclerView\n                    android:id=\"@+id/recyclerView\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"/>\n            </android.support.v4.widget.SwipeRefreshLayout>\n            <com.melnykov.fab.FloatingActionButton\n                android:id=\"@+id/fab\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"bottom|right\"\n                android:layout_margin=\"20dp\"\n                android:padding=\"4dp\"\n                android:src=\"@drawable/ic_edit_white\"\n                fab:fab_colorRipple=\"?attr/colorPrimary\"\n                fab:fab_colorNormal=\"?attr/colorPrimary\"\n                fab:fab_colorPressed=\"?attr/colorPrimaryDark\" />\n            <com.pnikosis.materialishprogress.ProgressWheel\n                android:id=\"@+id/progress_wheel\"\n                android:layout_width=\"75dp\"\n                android:layout_height=\"75dp\"\n                android:visibility=\"visible\"\n                android:layout_gravity=\"center\"\n                wheel:matProg_spinSpeed=\"1.2\"\n                wheel:matProg_barColor=\"?attr/colorPrimary\"\n                wheel:matProg_progressIndeterminate=\"true\" />\n            <include layout=\"@layout/toolbar_shadow_layout\"/>\n        </FrameLayout>\n        <!-- The navigation drawer -->\n        <LinearLayout\n            android:id=\"@+id/left_drawer\"\n            android:orientation=\"vertical\"\n            android:layout_gravity=\"start\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\">\n            <ListView android:id=\"@+id/left_drawer_listview\"\n                android:layout_width=\"@dimen/drawer_width\"\n                android:layout_height=\"0dp\"\n                android:layout_weight=\"1.0\"\n                android:choiceMode=\"singleChoice\"\n                android:divider=\"@android:color/transparent\"\n                android:dividerHeight=\"0dp\"\n                android:background=\"?attr/colorPrimary\"/>\n            <Button\n                android:text=\"@string/edit\"\n                android:id=\"@+id/edit_note_type\"\n                android:background=\"?attr/colorPrimary\"\n                android:layout_width=\"@dimen/drawer_width\"\n                android:textColor=\"@android:color/white\"\n                android:layout_height=\"?attr/listPreferredItemHeight\"\n                android:textAppearance=\"?android:attr/textAppearanceMedium\" />\n        </LinearLayout>\n\n    </android.support.v4.widget.DrawerLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_note.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tool=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:focusable=\"true\"\n    android:focusableInTouchMode=\"true\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <include layout=\"@layout/toolbar_layout\" />\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    <ScrollView\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:id=\"@+id/scroll_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:fadingEdge=\"none\"\n        android:scrollbars=\"none\"\n        android:cacheColorHint=\"@android:color/transparent\"\n        android:scrollingCache=\"false\"\n        android:overScrollMode=\"never\">\n        <LinearLayout\n            android:layout_margin=\"20dp\"\n            android:orientation=\"vertical\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n            <com.rengwuxian.materialedittext.MaterialEditText\n                style=\"@style/EditTextTheme\"\n                android:id=\"@+id/label_edit_text\"\n                android:textSize=\"@dimen/abc_text_size_large_material\"\n                app:met_primaryColor=\"?attr/colorPrimary\"\n                app:met_floatingLabel=\"highlight\"\n                app:met_floatingLabelText=\"@string/label\"\n                app:met_floatingLabelAlwaysShown=\"true\"\n                app:met_floatingLabelTextColor=\"?attr/colorPrimary\"/>\n            <com.rengwuxian.materialedittext.MaterialEditText\n                style=\"@style/EditTextTheme\"\n                android:id=\"@+id/content_edit_text\"\n                android:lineSpacingExtra=\"4dp\"\n                app:met_hideUnderline=\"true\"\n                app:met_primaryColor=\"?attr/colorPrimary\"\n                app:met_floatingLabel=\"highlight\"\n                app:met_floatingLabelAlwaysShown=\"true\"\n                app:met_floatingLabelTextColor=\"?attr/colorPrimary\"\n                app:met_floatingLabelText=\"@string/note_content\" />\n            <TextView\n                android:id=\"@+id/opr_time_line_text\"\n                android:layout_marginTop=\"6dp\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"@color/grey\"\n                android:gravity=\"end\"\n                android:textSize=\"@dimen/abc_text_size_small_material\"\n                android:lineSpacingExtra=\"4dp\"\n                android:layout_gravity=\"right\"\n                tool:text=\"015-5-25:14:01\" />\n            </LinearLayout>\n        </ScrollView>\n        <include layout=\"@layout/toolbar_shadow_layout\"/>\n    </FrameLayout>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_pay.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <include layout=\"@layout/toolbar_layout\" />\n    <include layout=\"@layout/toolbar_shadow_layout\"/>\n    <ImageView\n        android:layout_marginTop=\"80dp\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:id=\"@+id/alipay_img\"\n        android:src=\"@drawable/alipay_erweima\"\n        android:layout_gravity=\"center_horizontal\" />\n\n    <TextView\n        android:gravity=\"center\"\n        android:layout_marginTop=\"20dp\"\n        android:layout_width=\"200dp\"\n        android:lineSpacingExtra=\"6dp\"\n        android:layout_height=\"wrap_content\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        android:text=\"@string/pay_for_me_tip\"\n        android:layout_gravity=\"center_horizontal\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_setting.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <include layout=\"@layout/toolbar_layout\" />\n    <FrameLayout\n        android:id=\"@+id/fragment_content\"\n        android:background=\"@color/window_background\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <include layout=\"@layout/toolbar_shadow_layout\"/>\n    </FrameLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/colors_image_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:background=\"@android:color/transparent\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\">\n    <ImageView\n        android:id=\"@+id/img_1\"\n        android:layout_gravity=\"center\"\n        android:layout_width=\"@dimen/md_simplelist_icon\"\n        android:layout_height=\"@dimen/md_simplelist_icon\" />\n    <ImageView\n        android:id=\"@+id/img_2\"\n        android:layout_gravity=\"center\"\n        android:layout_width=\"20dp\"\n        android:layout_height=\"20dp\" />\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/colors_panel_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<GridView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\" android:layout_width=\"match_parent\"\n    android:numColumns=\"4\"\n    android:padding=\"@dimen/md_dialog_frame_margin\"\n    android:background=\"@android:color/transparent\"\n    android:listSelector=\"@android:color/transparent\"\n    android:horizontalSpacing=\"20dp\"\n    android:verticalSpacing=\"20dp\"\n    android:layout_height=\"match_parent\">\n</GridView>"
  },
  {
    "path": "app/src/main/res/layout/drawer_list_item_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:background=\"?android:attr/activatedBackgroundIndicator\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"?attr/listPreferredItemHeight\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        tools:text=\"Medium Text\"\n        android:id=\"@+id/textView\"\n        android:singleLine=\"true\"\n        android:gravity=\"center_vertical\"\n        android:padding=\"10dp\"\n        android:textColor=\"@android:color/white\"\n        android:layout_gravity=\"center_horizontal\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/edit_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.rengwuxian.materialedittext.MaterialEditText\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    style=\"@style/EditTextTheme\"\n    android:paddingTop=\"10dp\"\n    app:met_primaryColor=\"?attr/colorPrimary\"\n    app:met_floatingLabelTextColor=\"?attr/colorPrimary\" />"
  },
  {
    "path": "app/src/main/res/layout/md_simplelist_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"horizontal\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingLeft=\"@dimen/md_dialog_frame_margin\"\n    android:paddingStart=\"@dimen/md_dialog_frame_margin\"\n    android:paddingRight=\"@dimen/md_dialog_frame_margin\"\n    android:paddingEnd=\"@dimen/md_dialog_frame_margin\"\n    android:paddingTop=\"@dimen/md_simplelistitem_padding_top\"\n    android:paddingBottom=\"@dimen/md_simplelistitem_padding_top\"\n    android:gravity=\"start|center_vertical\"\n    android:minHeight=\"@dimen/md_listitem_height\">\n    <ImageView\n        android:id=\"@android:id/icon\"\n        android:layout_width=\"30dp\"\n        android:layout_height=\"30dp\"\n        tools:background=\"#f5f5f5\"\n        android:layout_marginRight=\"@dimen/md_simplelist_icon_margin\"\n        android:layout_marginEnd=\"@dimen/md_simplelist_icon_margin\"\n        android:scaleType=\"fitStart\"\n        tools:ignore=\"ContentDescription\" />\n\n    <TextView\n        android:id=\"@android:id/title\"\n        android:textColor=\"?android:textColorSecondary\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"@dimen/md_content_textsize\"\n        tools:text=\"Title\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/notes_item_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.balysv.materialripple.MaterialRippleLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"4dp\"\n    android:id=\"@+id/notes_item_root\"\n    android:alpha=\"0.7\"\n    android:background=\"@drawable/abc_popup_background_mtrl_mult\"\n    app:mrl_rippleOverlay=\"true\"\n    app:mrl_rippleColor=\"?attr/colorPrimary\">\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n            <LinearLayout\n                android:orientation=\"horizontal\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\">\n                <TextView\n                    android:id=\"@+id/note_label_text\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:paddingBottom=\"4dp\"\n                    android:paddingTop=\"6dp\"\n                    android:paddingLeft=\"6dp\"\n                    android:layout_weight=\"1.0\"\n                    tools:text=\"Label Text\"\n                    android:maxLines=\"14\"\n                    android:ellipsize=\"end\"\n                    android:lineSpacingExtra=\"2dp\"\n                    android:textColor=\"@color/dark_grey\"\n                    android:textSize=\"@dimen/abc_text_size_medium_material\"/>\n                <ImageButton\n                    android:id=\"@+id/note_more\"\n                    android:clickable=\"true\"\n                    android:focusable=\"true\"\n                    android:padding=\"4dp\"\n                    android:alpha=\"0.7\"\n                    android:background=\"?android:attr/selectableItemBackground\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:src=\"@drawable/ic_more_grey\"/>\n            </LinearLayout>\n            <TextView\n                android:id=\"@+id/note_content_text\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:padding=\"6dp\"\n                android:maxLines=\"40\"\n                android:lineSpacingExtra=\"2dp\"\n                android:ellipsize=\"end\"\n                android:textColor=\"#848484\"\n                android:textSize=\"@dimen/abc_text_size_small_material\"/>\n            <TextView\n                android:id=\"@+id/note_last_edit_text\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:padding=\"6dp\"\n                tools:text=\"2015-5-24:16:05\"\n                android:maxLines=\"1\"\n                android:ellipsize=\"end\"\n                android:textColor=\"?android:textColorSecondary\"\n                android:textSize=\"@dimen/abc_text_size_caption_material\"/>\n        </LinearLayout>\n</com.balysv.materialripple.MaterialRippleLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/toolbar_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v7.widget.Toolbar\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:theme=\"@style/ToolbarTheme\"\n    android:id=\"@+id/toolbar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"?attr/actionBarSize\"\n    android:background=\"?attr/colorPrimary\"/>"
  },
  {
    "path": "app/src/main/res/layout/toolbar_shadow_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<View\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"6dp\"\n    android:background=\"@drawable/toolbar_shadow\" />"
  },
  {
    "path": "app/src/main/res/menu/menu_about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/share\"\n        android:icon=\"@drawable/abc_ic_menu_share_mtrl_alpha\"\n        android:title=\"@string/share\"\n        app:showAsAction=\"ifRoom\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/action_search\"\n        android:icon=\"@drawable/abc_ic_search_api_mtrl_alpha\"\n        android:title=\"@string/search\"\n        app:showAsAction=\"ifRoom|collapseActionView\"\n        app:actionViewClass=\"android.support.v7.widget.SearchView\">\n    </item>\n\n    <item android:id=\"@+id/action_more\"\n        android:icon=\"@drawable/abc_ic_menu_moreoverflow_mtrl_alpha\"\n        android:title=\"@string/more\"\n        app:showAsAction=\"ifRoom\">\n        <menu>\n            <item\n                android:id=\"@+id/setting\"\n                android:title=\"@string/setting\" />\n            <item\n                android:id=\"@+id/sync\"\n                android:title=\"@string/sync\" />\n            <item\n                android:id=\"@+id/about\"\n                android:title=\"@string/about\" />\n        </menu>\n    </item>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_note.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/done\"\n        android:icon=\"@drawable/ic_done_white\"\n        android:title=\"@string/done\"\n        app:showAsAction=\"ifRoom\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_notes_more.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/edit\"\n        android:title=\"@string/edit\" />\n    <item\n        android:id=\"@+id/move_to_trash\"\n        android:title=\"@string/move_to_trash\" />\n    <item\n        android:id=\"@+id/delete_forever\"\n        android:title=\"@string/delete_forever\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"red\">#FF6347</color>\n    <color name=\"dark_red\">#F4511E</color>\n    <color name=\"accent_red\">#FF5722</color>\n\n    <color name=\"brown\">#795548</color>\n    <color name=\"dark_brown\">#5D4037</color>\n    <color name=\"accent_brown\">#795548</color>\n\n\n    <color name=\"blue\">#2196F3</color>\n    <color name=\"dark_blue\">#1976D2</color>\n    <color name=\"accent_blue\">#448AFF</color>\n\n    <color name=\"blue_grey\">#607D8B</color>\n    <color name=\"dark_blue_grey\">#455A64</color>\n    <color name=\"accent_blue_grey\">#607D8B</color>\n\n    <color name=\"yellow\">#FF9800</color>\n    <color name=\"dark_yellow\">#F57C00</color>\n    <color name=\"accent_yellow\">#FF9800</color>\n\n    <color name=\"deep_purple\">#673AB7</color>\n    <color name=\"dark_deep_purple\">#512DA8</color>\n    <color name=\"accent_deep_purple\">#7C4DFF</color>\n\n    <color name=\"pink\">#E91E63</color>\n    <color name=\"dark_pink\">#C2185B</color>\n    <color name=\"accent_pink\">#FF5722</color>\n\n    <color name=\"green\">#4CAF50</color>\n    <color name=\"dark_green\">#388E3C</color>\n    <color name=\"accent_green\">#4CAF50</color>\n\n    <color name=\"text_color_primary\">#212121</color>\n    <color name=\"text_second_color_primary\">#727272</color>\n\n    <color name=\"grey\" >#ffbebebe</color>\n    <color name=\"grey_1\">#9E9E9E</color>\n    <color name=\"dark_grey\">#FF080808</color>\n    <color name=\"light_grey\">#ffbebebe</color>\n    <color name=\"light_grey_1\">#FFEEEEEE</color>\n\n    <color name=\"drawer_scrim_color\">#88EEEEEE</color>\n    <color name=\"action_bar_title_color\">@android:color/white</color>\n    <color name=\"window_background\">@android:color/white</color>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <dimen name=\"md_simplelist_icon\">40dp</dimen>\n    <dimen name=\"md_simplelist_icon_margin\">18dp</dimen>\n    <dimen name=\"md_content_textsize\">16sp</dimen>\n    <dimen name=\"md_listitem_height\">48dp</dimen>\n    <dimen name=\"md_simplelistitem_padding_top\">8dp</dimen>\n    <dimen name=\"md_dialog_frame_margin\">24dp</dimen>\n    <dimen name=\"drawer_width\">200dp</dimen>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">极简笔记</string>\n    <string name=\"app_desc\">极简笔记，简洁精美的记事应用</string>\n    <string name=\"setting\">设置</string>\n    <string name=\"about\">关于</string>\n    <string name=\"exit\">退出</string>\n    <string name=\"search\">搜索</string>\n    <string name=\"more\">更多</string>\n    <string name=\"general_settings\">常规</string>\n    <string name=\"other\">其他</string>\n    <string name=\"advice_feedback\">意见反馈</string>\n    <string name=\"give_favor\">给应用点赞</string>\n    <string name=\"share_to_friends\">分享给朋友们</string>\n    <string name=\"show_note_history_log\">显示笔记全部操作记录</string>\n    <string name=\"sync\">同步</string>\n    <string name=\"show_note_history_log_summary\">开启显示笔记全部操作记录，将显示笔记所有的操作记录，否则只显示最新的操作记录</string>\n    <array name=\"drawer_content\">\n        <item>学习笔记</item>\n        <item>工作笔记</item>\n        <item>其他笔记</item>\n        <item>回收站</item>\n    </array>\n    <string name=\"note_log_text\" formatted=\"false\">%s\\u0020:\\u0020%s</string>\n    <string name=\"edit\">编辑</string>\n    <string name=\"move_to_trash\">移至回收站</string>\n    <string name=\"delete_forever\">永久删除</string>\n    <string name=\"right_hand_mode\">右手操作模式</string>\n    <string name=\"right_hand_mode_summary\">开启右手操作模式，侧边栏将从右边划开，默认从左边划开</string>\n    <string name=\"sure\">确定</string>\n    <string name=\"cancel\">取消</string>\n    <string name=\"delete_forever_message\">是否要永久地删除了该条笔记</string>\n    <string name=\"done\">完成</string>\n    <string name=\"label\">标签</string>\n    <string name=\"note_content\">笔记内容</string>\n    <string name=\"new_note\">新的笔记</string>\n    <string name=\"search_note\">搜索笔记</string>\n    <string name=\"edit_note\">编辑笔记</string>\n    <string name=\"view_note\">查看笔记</string>\n    <string name=\"show_note_history_log_key\">show_note_history_log_key</string>\n    <string name=\"right_hand_mode_key\">right_hand_mode_key</string>\n    <string name=\"move_success\">成功移除</string>\n    <string name=\"recover\">恢复</string>\n    <string name=\"create\">创建</string>\n    <string name=\"advice_feedback_key\">advice_feedback_key</string>\n    <string name=\"no_email_app_tip\">请先安装邮件应用并设置账户,或直接发送邮件至 lgpszu@163.com</string>\n    <string name=\"choose_account\">请选择账号</string>\n    <string name=\"sync_account\">同步账号</string>\n    <string name=\"sync_account_key\">sync_account_key</string>\n    <string name=\"no_account_tip\">请在手机设置中添加一个有效的邮箱账号</string>\n    <string name=\"multi_account_tip\">您的有效邮箱账号多于一个，请在设置中选择</string>\n    <string name=\"multi_account_choose_tip\">您的有效邮箱账号多于一个，请点击选择</string>\n    <string name=\"syncing\">正在后台同步中</string>\n    <string name=\"sync_success\">同步成功</string>\n    <string name=\"sync_fail\">同步失败，建议在网络好的时候进行同步</string>\n    <string name=\"pay_for_me_title\">觉得不错，随意打赏</string>\n    <string name=\"jianshu_blog\">简书博客</string>\n    <string name=\"project_home\">项目主页</string>\n    <string name=\"pay_for_me_tip\">如果觉得极简笔记对您有用，请随意打赏。</string>\n    <string name=\"pay_for_me\">随意打赏</string>\n    <string name=\"pay_for_me_key\">pay_for_me_key</string>\n    <string name=\"recycle_bin\">回收站</string>\n    <string name=\"move_to\">移回</string>\n    <string name=\"give_favor_key\">give_favor_key</string>\n    <string name=\"card_note_item_layout\">卡片式笔记</string>\n    <string name=\"card_note_item_layout_key\">card_note_item_layout_key</string>\n    <string name=\"not_save_note_leave_tip\">笔记已经发生变化，是否保存后再离开</string>\n    <string name=\"change_theme\">更换主题</string>\n    <string name=\"change_theme_key\">change_theme_key</string>\n    <string name=\"today\" formatted=\"false\">今天\\u0020%s</string>\n    <string name=\"before_day\" formatted=\"false\">%d\\u0020天前</string>\n    <string name=\"before_month\" formatted=\"false\">%d\\u0020个月前</string>\n    <string name=\"before_year\" formatted=\"false\">%d\\u0020年前</string>\n    <string name=\"share_text\" formatted=\"false\">极简笔记简洁好用，推荐你也来用用 %s\\u0020%s</string>\n    <string name=\"download_url\" >下载地址</string>\n    <string name=\"share\">分享到</string>\n    <string name=\"not_install_app\">请先安装相应客户端</string>\n    <array name=\"share_dialog_text\">\n        <item>微信好友</item>\n        <item>微信朋友圈</item>\n        <item>微信收藏</item>\n        <item>新浪微博</item>\n        <item>更多</item>\n    </array>\n    <string name=\"about_bottom_text\">Created by Lguipeng in Shenzhen</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppBaseTheme\" parent=\"Theme.AppCompat.NoActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"android:fitsSystemWindows\">true</item>\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n        <item name=\"android:textColorPrimary\">@color/text_color_primary</item>\n        <item name=\"android:textColorSecondary\">@color/text_second_color_primary</item>\n        <item name=\"android:windowBackground\">@color/window_background</item>\n        <item name=\"searchViewStyle\">@style/SearchViewStyle</item>\n        <item name=\"android:autoCompleteTextViewStyle\">@style/AutoCompleteTextView</item>\n        <item name=\"popupTheme\">@style/popupTheme</item>\n        <item name=\"popupMenuStyle\">@style/popupMenuStyle</item>\n        <item name=\"android:activatedBackgroundIndicator\">@drawable/activated_background</item>\n        <item name=\"selectableItemBackground\">@drawable/selectable_background</item>\n    </style>\n\n    <style name=\"AppBaseTheme.Dark\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n\n        <item name=\"android:fitsSystemWindows\">true</item>\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n        <item name=\"android:textColorPrimary\">@color/text_color_primary</item>\n        <item name=\"android:textColorSecondary\">@color/text_second_color_primary</item>\n        <item name=\"android:windowBackground\">@color/window_background</item>\n        <item name=\"searchViewStyle\">@style/SearchViewStyle</item>\n        <item name=\"android:autoCompleteTextViewStyle\">@style/AutoCompleteTextView</item>\n        <item name=\"popupTheme\">@style/popupTheme</item>\n        <item name=\"popupMenuStyle\">@style/popupMenuStyle</item>\n\n        <item name=\"android:activatedBackgroundIndicator\">@drawable/activated_background</item>\n        <item name=\"selectableItemBackground\">@drawable/selectable_background</item>\n    </style>\n\n    <style name=\"BaseDialogTheme\" parent=\"Theme.AppCompat.Light.Dialog\">\n        <item name=\"android:textColorPrimary\">@color/text_color_primary</item>\n        <item name=\"android:textColorSecondary\">@color/text_second_color_primary</item>\n        <item name=\"android:windowEnterAnimation\">@anim/abc_popup_enter</item>\n        <item name=\"android:windowExitAnimation\">@anim/abc_popup_exit</item>\n    </style>\n\n    <style name=\"AppTheme\" parent=\"AppBaseTheme.Dark\">\n        <!-- All customizations that are NOT specific to a particular API-level can go here. -->\n    </style>\n\n    <style name=\"SearchViewStyle\" parent=\"Widget.AppCompat.SearchView\">\n        <item name=\"queryBackground\">@android:color/transparent</item>\n    </style>\n\n    <style name=\"popupTheme\" parent=\"AppBaseTheme.Dark\">\n        <item name=\"android:textColor\">@android:color/black</item>\n    </style>\n\n    <style name=\"popupMenuStyle\" parent=\"Base.Widget.AppCompat.PopupMenu.Overflow\">\n    </style>\n\n    <style name=\"AutoCompleteTextView\" parent=\"Widget.AppCompat.AutoCompleteTextView\">\n        <item name=\"android:textColor\">@android:color/white</item>\n        <item name=\"android:background\">@null</item>\n        <item name=\"android:textColorHint\">@android:color/white</item>\n    </style>\n\n    <style name=\"ToolbarTheme\" parent=\"AppBaseTheme\">\n        <item name=\"android:textColorPrimary\">@android:color/white</item>\n        <item name=\"android:textColorSecondary\">@android:color/white</item>\n        <item name=\"colorControlActivated\">@android:color/white</item>\n    </style>\n\n\n    <style name=\"EditTextTheme\">\n        <item name=\"android:textSize\">@dimen/abc_text_size_medium_material</item>\n        <item name=\"android:textColor\">@android:color/black</item>\n\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n    </style>\n\n\n    <style name=\"RedTheme\" parent=\"AppBaseTheme.Dark\">\n        <item name=\"colorPrimary\">@color/red</item>\n        <item name=\"colorPrimaryDark\">@color/dark_red</item>\n        <item name=\"colorAccent\">@color/accent_red</item>\n    </style>\n\n    <style name=\"RedDialogTheme\" parent=\"BaseDialogTheme\">\n        <item name=\"colorPrimary\">@color/red</item>\n        <item name=\"colorPrimaryDark\">@color/dark_red</item>\n        <item name=\"colorAccent\">@color/accent_red</item>\n    </style>\n\n    <style name=\"BrownTheme\" parent=\"AppBaseTheme.Dark\">\n        <item name=\"colorPrimary\">@color/brown</item>\n        <item name=\"colorPrimaryDark\">@color/dark_brown</item>\n        <item name=\"colorAccent\">@color/accent_brown</item>\n    </style>\n\n    <style name=\"BrownDialogTheme\" parent=\"BaseDialogTheme\">\n        <item name=\"colorPrimary\">@color/brown</item>\n        <item name=\"colorPrimaryDark\">@color/dark_brown</item>\n        <item name=\"colorAccent\">@color/accent_brown</item>\n    </style>\n\n    <style name=\"BlueTheme\" parent=\"AppBaseTheme.Dark\">\n        <item name=\"colorPrimary\">@color/blue</item>\n        <item name=\"colorPrimaryDark\">@color/dark_blue</item>\n        <item name=\"colorAccent\">@color/accent_blue</item>\n    </style>\n\n    <style name=\"BlueDialogTheme\" parent=\"BaseDialogTheme\">\n        <item name=\"colorPrimary\">@color/blue</item>\n        <item name=\"colorPrimaryDark\">@color/dark_blue</item>\n        <item name=\"colorAccent\">@color/accent_blue</item>\n    </style>\n\n    <style name=\"BlueGreyTheme\" parent=\"AppBaseTheme.Dark\">\n        <item name=\"colorPrimary\">@color/blue_grey</item>\n        <item name=\"colorPrimaryDark\">@color/dark_blue_grey</item>\n        <item name=\"colorAccent\">@color/accent_blue_grey</item>\n    </style>\n\n    <style name=\"BlueGreyDialogTheme\" parent=\"BaseDialogTheme\">\n        <item name=\"colorPrimary\">@color/blue_grey</item>\n        <item name=\"colorPrimaryDark\">@color/dark_blue_grey</item>\n        <item name=\"colorAccent\">@color/accent_blue_grey</item>\n    </style>\n\n    <style name=\"YellowTheme\" parent=\"AppBaseTheme.Dark\">\n        <item name=\"colorPrimary\">@color/yellow</item>\n        <item name=\"colorPrimaryDark\">@color/dark_yellow</item>\n        <item name=\"colorAccent\">@color/accent_yellow</item>\n    </style>\n\n    <style name=\"YellowDialogTheme\" parent=\"BaseDialogTheme\">\n        <item name=\"colorPrimary\">@color/yellow</item>\n        <item name=\"colorPrimaryDark\">@color/dark_yellow</item>\n        <item name=\"colorAccent\">@color/accent_yellow</item>\n    </style>\n\n    <style name=\"DeepPurpleTheme\" parent=\"AppBaseTheme.Dark\">\n        <item name=\"colorPrimary\">@color/deep_purple</item>\n        <item name=\"colorPrimaryDark\">@color/dark_deep_purple</item>\n        <item name=\"colorAccent\">@color/accent_deep_purple</item>\n    </style>\n\n    <style name=\"DeepPurpleDialogTheme\" parent=\"BaseDialogTheme\">\n        <item name=\"colorPrimary\">@color/deep_purple</item>\n        <item name=\"colorPrimaryDark\">@color/dark_deep_purple</item>\n        <item name=\"colorAccent\">@color/accent_deep_purple</item>\n    </style>\n\n    <style name=\"PinkTheme\" parent=\"AppBaseTheme.Dark\">\n        <item name=\"colorPrimary\">@color/pink</item>\n        <item name=\"colorPrimaryDark\">@color/dark_pink</item>\n        <item name=\"colorAccent\">@color/accent_pink</item>\n    </style>\n\n    <style name=\"PinkDialogTheme\" parent=\"BaseDialogTheme\">\n        <item name=\"colorPrimary\">@color/pink</item>\n        <item name=\"colorPrimaryDark\">@color/dark_pink</item>\n        <item name=\"colorAccent\">@color/accent_pink</item>\n    </style>\n\n    <style name=\"GreenTheme\" parent=\"AppBaseTheme.Dark\">\n        <item name=\"colorPrimary\">@color/green</item>\n        <item name=\"colorPrimaryDark\">@color/dark_green</item>\n        <item name=\"colorAccent\">@color/accent_green</item>\n    </style>\n\n    <style name=\"GreenDialogTheme\" parent=\"BaseDialogTheme\">\n        <item name=\"colorPrimary\">@color/green</item>\n        <item name=\"colorPrimaryDark\">@color/dark_green</item>\n        <item name=\"colorAccent\">@color/accent_green</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/xml/prefs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    >\n    <com.jenzz.materialpreference.PreferenceCategory android:title=\"@string/general_settings\">\n        <com.jenzz.materialpreference.SwitchPreference\n            android:key=\"@string/right_hand_mode_key\"\n            android:title=\"@string/right_hand_mode\"\n            android:summary=\"@string/right_hand_mode_summary\"/>\n        <com.jenzz.materialpreference.CheckBoxPreference\n            android:key=\"@string/show_note_history_log_key\"\n            android:title=\"@string/show_note_history_log\"\n            android:defaultValue=\"true\"\n            android:summary=\"@string/show_note_history_log_summary\"/>\n        <com.jenzz.materialpreference.CheckBoxPreference\n            android:key=\"@string/card_note_item_layout_key\"\n            android:title=\"@string/card_note_item_layout\"/>\n        <com.jenzz.materialpreference.Preference\n            android:key=\"@string/sync_account_key\"\n            android:title=\"@string/sync_account\"/>\n        <com.jenzz.materialpreference.Preference\n            android:key=\"@string/change_theme_key\"\n            android:title=\"@string/change_theme\"/>\n    </com.jenzz.materialpreference.PreferenceCategory>\n\n    <com.jenzz.materialpreference.PreferenceCategory android:title=\"@string/other\">\n        <com.jenzz.materialpreference.Preference\n            android:key=\"@string/advice_feedback_key\"\n            android:title=\"@string/advice_feedback\"/>\n        <com.jenzz.materialpreference.Preference\n            android:key=\"@string/give_favor_key\"\n            android:title=\"@string/give_favor\"/>\n        <com.jenzz.materialpreference.Preference\n            android:key=\"@string/pay_for_me_key\"\n            android:title=\"@string/pay_for_me_title\"/>\n    </com.jenzz.materialpreference.PreferenceCategory>\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/searchable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<searchable xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:label=\"@string/search\"\n    android:hint=\"@string/search_note\">\n</searchable>"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n        maven {\n            url \"http://mvn.leancloud.cn/nexus/content/repositories/releases\"\n        }\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:1.2.3'\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        jcenter()\n        maven {\n            url \"http://mvn.leancloud.cn/nexus/content/repositories/releases\"\n        }\n    }\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Apr 10 15:27:10 PDT 2013\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.2.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.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\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\nANDROID_BUILD_COMPILE_SDK_VERSION=22\nANDROID_BUILD_TARGET_SDK_VERSION=22\nANDROID_BUILD_TOOLS_VERSION=22.0.1\nMIN_SDK_VERSION=14\nTARGET_SDK_VERSION=22\nVERSION_CODE=3\nVERSION_NAME=1.1.2"
  },
  {
    "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# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\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\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\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\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": "orm-library/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "orm-library/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 22\n    buildToolsVersion \"22.0.1\"\n\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 22\n        versionCode 1\n        versionName \"1.0\"\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}\n"
  },
  {
    "path": "orm-library/orm-library.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module external.linked.project.id=\":orm-library\" external.linked.project.path=\"$MODULE_DIR$\" external.root.project.path=\"$MODULE_DIR$/..\" external.system.id=\"GRADLE\" external.system.module.group=\"Notes\" external.system.module.version=\"unspecified\" type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android-gradle\" name=\"Android-Gradle\">\n      <configuration>\n        <option name=\"GRADLE_PROJECT_PATH\" value=\":orm-library\" />\n      </configuration>\n    </facet>\n    <facet type=\"android\" name=\"Android\">\n      <configuration>\n        <option name=\"SELECTED_BUILD_VARIANT\" value=\"debug\" />\n        <option name=\"SELECTED_TEST_ARTIFACT\" value=\"_android_test_\" />\n        <option name=\"ASSEMBLE_TASK_NAME\" value=\"assembleDebug\" />\n        <option name=\"COMPILE_JAVA_TASK_NAME\" value=\"compileDebugSources\" />\n        <option name=\"ASSEMBLE_TEST_TASK_NAME\" value=\"assembleDebugAndroidTest\" />\n        <option name=\"COMPILE_JAVA_TEST_TASK_NAME\" value=\"compileDebugAndroidTestSources\" />\n        <afterSyncTasks>\n          <task>generateDebugAndroidTestSources</task>\n          <task>generateDebugSources</task>\n        </afterSyncTasks>\n        <option name=\"ALLOW_USER_CONFIGURATION\" value=\"false\" />\n        <option name=\"MANIFEST_FILE_RELATIVE_PATH\" value=\"/src/main/AndroidManifest.xml\" />\n        <option name=\"RES_FOLDER_RELATIVE_PATH\" value=\"/src/main/res\" />\n        <option name=\"RES_FOLDERS_RELATIVE_PATH\" value=\"file://$MODULE_DIR$/src/main/res\" />\n        <option name=\"ASSETS_FOLDER_RELATIVE_PATH\" value=\"/src/main/assets\" />\n        <option name=\"LIBRARY_PROJECT\" value=\"true\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" LANGUAGE_LEVEL=\"JDK_1_7\" inherit-compiler-output=\"false\">\n    <output url=\"file://$MODULE_DIR$/build/intermediates/classes/debug\" />\n    <output-test url=\"file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug\" />\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/r/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/aidl/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/buildConfig/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/rs/debug\" isTestSource=\"false\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/rs/debug\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/generated/debug\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/r/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug\" isTestSource=\"true\" generated=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/res\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/assets\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/aidl\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/jni\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/debug/rs\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/res\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/resources\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/assets\" type=\"java-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/aidl\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/jni\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/main/rs\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/res\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/resources\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/assets\" type=\"java-test-resource\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/aidl\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/java\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/jni\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src/androidTest/rs\" isTestSource=\"true\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/assets\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/bundles\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/classes\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dependency-cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dex\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/dex-cache\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/incremental\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/jacoco\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/javaResources\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/libs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/lint\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/manifests\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/ndk\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/pre-dexed\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/proguard\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/res\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/rs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/intermediates/symbols\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/outputs\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/reports\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/test-results\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build/tmp\" />\n    </content>\n    <orderEntry type=\"jdk\" jdkName=\"Android API 22 Platform\" jdkType=\"Android SDK\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": "orm-library/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in E:\\adt-bundle-windows-x86_64-20131030/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\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"
  },
  {
    "path": "orm-library/src/androidTest/java/com/lguipeng/library/ApplicationTest.java",
    "content": "package com.lguipeng.library;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "orm-library/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" package=\"com.lguipeng.library\">\n\n    <application android:allowBackup=\"true\" android:label=\"@string/app_name\">\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/FinalDb.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.Serializable;\nimport java.lang.String;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport net.tsz.afinal.db.sqlite.CursorUtils;\nimport net.tsz.afinal.db.sqlite.DbModel;\nimport net.tsz.afinal.db.sqlite.ManyToOneLazyLoader;\nimport net.tsz.afinal.db.sqlite.OneToManyLazyLoader;\nimport net.tsz.afinal.db.sqlite.SqlBuilder;\nimport net.tsz.afinal.db.sqlite.SqlInfo;\nimport net.tsz.afinal.db.table.KeyValue;\nimport net.tsz.afinal.db.table.ManyToOne;\nimport net.tsz.afinal.db.table.OneToMany;\nimport net.tsz.afinal.db.table.TableInfo;\nimport net.tsz.afinal.exception.DbException;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.util.Log;\n\npublic class FinalDb{\n\n\tprivate static final String TAG = \"FinalDb\";\n\n\tprivate static HashMap<String, FinalDb> daoMap = new HashMap<String, FinalDb>();\n\n\tprivate SQLiteDatabase db;\n\tprivate DaoConfig config;\n\n\tprivate FinalDb(DaoConfig config) {\n\t\tif (config == null)\n\t\t\tthrow new DbException(\"daoConfig is null\");\n\t\tif (config.getContext() == null)\n\t\t\tthrow new DbException(\"android context is null\");\n\t\tif (config.getTargetDirectory() != null\n\t\t\t\t&& config.getTargetDirectory().trim().length() > 0) {\n\t\t\tthis.db = createDbFileOnSDCard(config.getTargetDirectory(),\n\t\t\t\t\tconfig.getDbName());\n\t\t} else {\n\t\t\tthis.db = new SqliteDbHelper(config.getContext()\n\t\t\t\t\t.getApplicationContext(), config.getDbName(),\n\t\t\t\t\tconfig.getDbVersion(), config.getDbUpdateListener())\n\t\t\t\t\t.getWritableDatabase();\n\t\t}\n\t\tthis.config = config;\n\t}\n\n\tprivate synchronized static FinalDb getInstance(DaoConfig daoConfig) {\n\t\tFinalDb dao = daoMap.get(daoConfig.getDbName());\n\t\tif (dao == null) {\n\t\t\tdao = new FinalDb(daoConfig);\n\t\t\tdaoMap.put(daoConfig.getDbName(), dao);\n\t\t}\n\t\treturn dao;\n\t}\n\n\t/**\n\t * 创建FinalDb\n\t * \n\t * @param context\n\t */\n\tpublic static FinalDb create(Context context) {\n\t\tDaoConfig config = new DaoConfig();\n\t\tconfig.setContext(context);\n\t\treturn create(config);\n\t}\n\n\t/**\n\t * 创建FinalDb\n\t * \n\t * @param context\n\t * @param isDebug\n\t *            是否是debug模式（debug模式进行数据库操作的时候将会打印sql语句）\n\t */\n\tpublic static FinalDb create(Context context, boolean isDebug) {\n\t\tDaoConfig config = new DaoConfig();\n\t\tconfig.setContext(context);\n\t\tconfig.setDebug(isDebug);\n\t\treturn create(config);\n\n\t}\n\n\t/**\n\t * 创建FinalDb\n\t * \n\t * @param context\n\t * @param dbName\n\t *            数据库名称\n\t */\n\tpublic static FinalDb create(Context context, String dbName) {\n\t\tDaoConfig config = new DaoConfig();\n\t\tconfig.setContext(context);\n\t\tconfig.setDbName(dbName);\n\t\treturn create(config);\n\t}\n\n\t/**\n\t * 创建 FinalDb\n\t * \n\t * @param context\n\t * @param dbName\n\t *            数据库名称\n\t * @param isDebug\n\t *            是否为debug模式（debug模式进行数据库操作的时候将会打印sql语句）\n\t */\n\tpublic static FinalDb create(Context context, String dbName, boolean isDebug) {\n\t\tDaoConfig config = new DaoConfig();\n\t\tconfig.setContext(context);\n\t\tconfig.setDbName(dbName);\n\t\tconfig.setDebug(isDebug);\n\t\treturn create(config);\n\t}\n\n\t/**\n\t * 创建FinalDb\n\t * \n\t * @param context\n\t * @param dbName\n\t *            数据库名称\n\t */\n\tpublic static FinalDb create(Context context, String targetDirectory,\n\t\t\tString dbName) {\n\t\tDaoConfig config = new DaoConfig();\n\t\tconfig.setContext(context);\n\t\tconfig.setDbName(dbName);\n\t\tconfig.setTargetDirectory(targetDirectory);\n\t\treturn create(config);\n\t}\n\n\t/**\n\t * 创建 FinalDb\n\t * \n\t * @param context\n\t * @param dbName\n\t *            数据库名称\n\t * @param isDebug\n\t *            是否为debug模式（debug模式进行数据库操作的时候将会打印sql语句）\n\t */\n\tpublic static FinalDb create(Context context, String targetDirectory,\n\t\t\tString dbName, boolean isDebug) {\n\t\tDaoConfig config = new DaoConfig();\n\t\tconfig.setContext(context);\n\t\tconfig.setTargetDirectory(targetDirectory);\n\t\tconfig.setDbName(dbName);\n\t\tconfig.setDebug(isDebug);\n\t\treturn create(config);\n\t}\n\n\t/**\n\t * 创建 FinalDb\n\t * \n\t * @param context\n\t *            上下文\n\t * @param dbName\n\t *            数据库名字\n\t * @param isDebug\n\t *            是否是调试模式：调试模式会log出sql信息\n\t * @param dbVersion\n\t *            数据库版本信息\n\t * @param dbUpdateListener\n\t *            数据库升级监听器：如果监听器为null，升级的时候将会清空所所有的数据\n\t * @return\n\t */\n\tpublic static FinalDb create(Context context, String dbName,\n\t\t\tboolean isDebug, int dbVersion, DbUpdateListener dbUpdateListener) {\n\t\tDaoConfig config = new DaoConfig();\n\t\tconfig.setContext(context);\n\t\tconfig.setDbName(dbName);\n\t\tconfig.setDebug(isDebug);\n\t\tconfig.setDbVersion(dbVersion);\n\t\tconfig.setDbUpdateListener(dbUpdateListener);\n\t\treturn create(config);\n\t}\n\n\t/**\n\t * \n\t * @param context\n\t *            上下文\n\t * @param targetDirectory\n\t *            db文件路径，可以配置为sdcard的路径\n\t * @param dbName\n\t *            数据库名字\n\t * @param isDebug\n\t *            是否是调试模式：调试模式会log出sql信息\n\t * @param dbVersion\n\t *            数据库版本信息\n\t * @param dbUpdateListener数据库升级监听器\n\t *            ：如果监听器为null，升级的时候将会清空所所有的数据\n\t * @return\n\t */\n\tpublic static FinalDb create(Context context, String targetDirectory,\n\t\t\tString dbName, boolean isDebug, int dbVersion,\n\t\t\tDbUpdateListener dbUpdateListener) {\n\t\tDaoConfig config = new DaoConfig();\n\t\tconfig.setContext(context);\n\t\tconfig.setTargetDirectory(targetDirectory);\n\t\tconfig.setDbName(dbName);\n\t\tconfig.setDebug(isDebug);\n\t\tconfig.setDbVersion(dbVersion);\n\t\tconfig.setDbUpdateListener(dbUpdateListener);\n\t\treturn create(config);\n\t}\n\n\t/**\n\t * 创建FinalDb\n\t * \n\t * @param daoConfig\n\t * @return\n\t */\n\tpublic static FinalDb create(DaoConfig daoConfig) {\n\t\treturn getInstance(daoConfig);\n\t}\n\n\t/**\n\t * 保存数据库，速度要比save快\n\t * \n\t * @param entity\n\t */\n\tpublic void save(Object entity) {\n\t\tcheckTableExist(entity.getClass());\n\t\texeSqlInfo(SqlBuilder.buildInsertSql(entity));\n\t}\n\n\t/**\n\t * 保存数据到数据库<br />\n\t * <b>注意：</b><br />\n\t * 保存成功后，entity的主键将被赋值（或更新）为数据库的主键， 只针对自增长的id有效\n\t * \n\t * @param entity\n\t *            要保存的数据\n\t * @return ture： 保存成功 false:保存失败\n\t */\n\tpublic boolean saveBindId(Object entity) {\n\t\tcheckTableExist(entity.getClass());\n\t\tList<KeyValue> entityKvList = SqlBuilder\n\t\t\t\t.getSaveKeyValueListByEntity(entity);\n\t\tif (entityKvList != null && entityKvList.size() > 0) {\n\t\t\tTableInfo tf = TableInfo.get(entity.getClass());\n\t\t\tContentValues cv = new ContentValues();\n\t\t\tinsertContentValues(entityKvList, cv);\n\t\t\tLong id = db.insert(tf.getTableName(), null, cv);\n\t\t\tif (id == -1)\n\t\t\t\treturn false;\n\t\t\ttf.getId().setValue(entity, id);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * 把List<KeyValue>数据存储到ContentValues\n\t * \n\t * @param list\n\t * @param cv\n\t */\n\tprivate void insertContentValues(List<KeyValue> list, ContentValues cv) {\n\t\tif (list != null && cv != null) {\n\t\t\tfor (KeyValue kv : list) {\n\t\t\t\tcv.put(kv.getKey(), kv.getValue().toString());\n\t\t\t}\n\t\t} else {\n\t\t\tLog.w(TAG,\n\t\t\t\t\t\"insertContentValues: List<KeyValue> is empty or ContentValues is empty!\");\n\t\t}\n\n\t}\n\n\t/**\n\t * 更新数据 （主键ID必须不能为空）\n\t * \n\t * @param entity\n\t */\n\tpublic void update(Object entity) {\n\t\tcheckTableExist(entity.getClass());\n\t\texeSqlInfo(SqlBuilder.getUpdateSqlAsSqlInfo(entity));\n\t}\n\n\t/**\n\t * 根据条件更新数据\n\t * \n\t * @param entity\n\t * @param strWhere\n\t *            条件为空的时候，将会更新所有的数据\n\t */\n\tpublic void update(Object entity, String strWhere) {\n\t\tcheckTableExist(entity.getClass());\n\t\texeSqlInfo(SqlBuilder.getUpdateSqlAsSqlInfo(entity, strWhere));\n\t}\n\n\t/**\n\t * 删除数据\n\t * \n\t * @param entity\n\t *            entity的主键不能为空\n\t */\n\tpublic void delete(Object entity) {\n\t\tcheckTableExist(entity.getClass());\n\t\texeSqlInfo(SqlBuilder.buildDeleteSql(entity));\n\t}\n\n\t/**\n\t * 根据主键删除数据\n\t * \n\t * @param clazz\n\t *            要删除的实体类\n\t * @param id\n\t *            主键值\n\t */\n\tpublic void deleteById(Class<?> clazz, Object id) {\n\t\tcheckTableExist(clazz);\n\t\texeSqlInfo(SqlBuilder.buildDeleteSql(clazz, id));\n\t}\n\n\t/**\n\t * 根据条件删除数据\n\t * \n\t * @param clazz\n\t * @param strWhere\n\t *            条件为空的时候 将会删除所有的数据\n\t */\n\tpublic void deleteByWhere(Class<?> clazz, String strWhere) {\n\t\tcheckTableExist(clazz);\n\t\tString sql = SqlBuilder.buildDeleteSql(clazz, strWhere);\n\t\tdebugSql(sql);\n\t\tdb.execSQL(sql);\n\t}\n\n\t/**\n\t * 删除表的所有数据\n\t * \n\t * @param clazz\n\t */\n\tpublic void deleteAll(Class<?> clazz) {\n\t\tcheckTableExist(clazz);\n\t\tString sql = SqlBuilder.buildDeleteSql(clazz, null);\n\t\tdebugSql(sql);\n\t\tdb.execSQL(sql);\n\t}\n\n\t/**\n\t * 删除指定的表\n\t * \n\t * @param clazz\n\t */\n\tpublic void dropTable(Class<?> clazz) {\n\t\tcheckTableExist(clazz);\n\t\tTableInfo table = TableInfo.get(clazz);\n\t\tString sql = \"DROP TABLE \" + table.getTableName();\n\t\tdebugSql(sql);\n\t\tdb.execSQL(sql);\n\t}\n\n\t/**\n\t * 删除所有数据表\n\t */\n\tpublic void dropDb() {\n\t\tCursor cursor = db.rawQuery(\n\t\t\t\t\"SELECT name FROM sqlite_master WHERE type ='table' AND name != 'sqlite_sequence'\", null);\n\t\tif (cursor != null) {\n\t\t\twhile (cursor.moveToNext()) {\n\t\t\t\tdb.execSQL(\"DROP TABLE \" + cursor.getString(0));\n\t\t\t}\n\t\t}\n\t\tif (cursor != null) {\n\t\t\tcursor.close();\n\t\t\tcursor = null;\n\t\t}\n\t}\n\n\tprivate void exeSqlInfo(SqlInfo sqlInfo) {\n\t\tif (sqlInfo != null) {\n\t\t\tdebugSql(sqlInfo.getSql());\n\t\t\tdb.execSQL(sqlInfo.getSql(), sqlInfo.getBindArgsAsArray());\n\t\t} else {\n\t\t\tLog.e(TAG, \"save error:sqlInfo is null\");\n\t\t}\n\t}\n\n\t/**\n\t * 根据主键查找数据（默认不查询多对一或者一对多的关联数据）\n\t * \n\t * @param id\n\t * @param clazz\n\t */\n\tpublic <T> T findById(Object id, Class<T> clazz) {\n\t\tcheckTableExist(clazz);\n\t\tSqlInfo sqlInfo = SqlBuilder.getSelectSqlAsSqlInfo(clazz, id);\n\t\tif (sqlInfo != null) {\n\t\t\tdebugSql(sqlInfo.getSql());\n\t\t\tCursor cursor = db.rawQuery(sqlInfo.getSql(),\n\t\t\t\t\tsqlInfo.getBindArgsAsStringArray());\n\t\t\ttry {\n\t\t\t\tif (cursor.moveToNext()) {\n\t\t\t\t\treturn CursorUtils.getEntity(cursor, clazz, this);\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t} finally {\n\t\t\t\tcursor.close();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据主键查找，同时查找“多对一”的数据（如果有多个“多对一”属性，则查找所有的“多对一”属性）\n\t * \n\t * @param id\n\t * @param clazz\n\t */\n\tpublic <T> T findWithManyToOneById(Object id, Class<T> clazz) {\n\t\tcheckTableExist(clazz);\n\t\tString sql = SqlBuilder.getSelectSQL(clazz, id);\n\t\tdebugSql(sql);\n\t\tDbModel dbModel = findDbModelBySQL(sql);\n\t\tif (dbModel != null) {\n\t\t\tT entity = CursorUtils.dbModel2Entity(dbModel, clazz);\n\t\t\treturn loadManyToOne(dbModel, entity, clazz);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据条件查找，同时查找“多对一”的数据（只查找findClass中的类的数据）\n\t * \n\t * @param id\n\t * @param clazz\n\t * @param findClass\n\t *            要查找的类\n\t */\n\tpublic <T> T findWithManyToOneById(Object id, Class<T> clazz,\n\t\t\tClass<?>... findClass) {\n\t\tcheckTableExist(clazz);\n\t\tString sql = SqlBuilder.getSelectSQL(clazz, id);\n\t\tdebugSql(sql);\n\t\tDbModel dbModel = findDbModelBySQL(sql);\n\t\tif (dbModel != null) {\n\t\t\tT entity = CursorUtils.dbModel2Entity(dbModel, clazz);\n\t\t\treturn loadManyToOne(dbModel, entity, clazz, findClass);\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 将entity中的“多对一”的数据填充满 如果是懒加载填充，则dbModel参数可为null\n\t * \n\t * @param clazz\n\t * @param entity\n\t * @param <T>\n\t * @return\n\t */\n\tpublic <T> T loadManyToOne(DbModel dbModel, T entity, Class<T> clazz,\n\t\t\tClass<?>... findClass) {\n\t\tif (entity != null) {\n\t\t\ttry {\n\t\t\t\tCollection<ManyToOne> manys = TableInfo.get(clazz).manyToOneMap\n\t\t\t\t\t\t.values();\n\t\t\t\tfor (ManyToOne many : manys) {\n\n\t\t\t\t\tObject id = null;\n\t\t\t\t\tif (dbModel != null) {\n\t\t\t\t\t\tid = dbModel.get(many.getColumn());\n\t\t\t\t\t} else if (many.getValue(entity).getClass() == ManyToOneLazyLoader.class\n\t\t\t\t\t\t\t&& many.getValue(entity) != null) {\n\t\t\t\t\t\tid = ((ManyToOneLazyLoader) many.getValue(entity))\n\t\t\t\t\t\t\t\t.getFieldValue();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (id != null) {\n\t\t\t\t\t\tboolean isFind = false;\n\t\t\t\t\t\tif (findClass == null || findClass.length == 0) {\n\t\t\t\t\t\t\tisFind = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (Class<?> mClass : findClass) {\n\t\t\t\t\t\t\tif (many.getManyClass() == mClass) {\n\t\t\t\t\t\t\t\tisFind = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (isFind) {\n\n\t\t\t\t\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\t\t\t\t\tT manyEntity = (T) findById(\n\t\t\t\t\t\t\t\t\tInteger.valueOf(id.toString()),\n\t\t\t\t\t\t\t\t\tmany.getManyClass());\n\t\t\t\t\t\t\tif (manyEntity != null) {\n\t\t\t\t\t\t\t\tif (many.getValue(entity).getClass() == ManyToOneLazyLoader.class) {\n\t\t\t\t\t\t\t\t\tif (many.getValue(entity) == null) {\n\t\t\t\t\t\t\t\t\t\tmany.setValue(\n\t\t\t\t\t\t\t\t\t\t\t\tentity,\n\t\t\t\t\t\t\t\t\t\t\t\tnew ManyToOneLazyLoader(entity,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tclazz,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tmany.getManyClass(),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tthis));\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t((ManyToOneLazyLoader) many\n\t\t\t\t\t\t\t\t\t\t\t.getValue(entity)).set(manyEntity);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tmany.setValue(entity, manyEntity);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn entity;\n\t}\n\n\t/**\n\t * 根据主键查找，同时查找“一对多”的数据（如果有多个“一对多”属性，则查找所有的一对多”属性）\n\t * \n\t * @param id\n\t * @param clazz\n\t */\n\tpublic <T> T findWithOneToManyById(Object id, Class<T> clazz) {\n\t\tcheckTableExist(clazz);\n\t\tString sql = SqlBuilder.getSelectSQL(clazz, id);\n\t\tdebugSql(sql);\n\t\tDbModel dbModel = findDbModelBySQL(sql);\n\t\tif (dbModel != null) {\n\t\t\tT entity = CursorUtils.dbModel2Entity(dbModel, clazz);\n\t\t\treturn loadOneToMany(entity, clazz);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据主键查找，同时查找“一对多”的数据（只查找findClass中的“一对多”）\n\t * \n\t * @param id\n\t * @param clazz\n\t * @param findClass\n\t */\n\tpublic <T> T findWithOneToManyById(Object id, Class<T> clazz,\n\t\t\tClass<?>... findClass) {\n\t\tcheckTableExist(clazz);\n\t\tString sql = SqlBuilder.getSelectSQL(clazz, id);\n\t\tdebugSql(sql);\n\t\tDbModel dbModel = findDbModelBySQL(sql);\n\t\tif (dbModel != null) {\n\t\t\tT entity = CursorUtils.dbModel2Entity(dbModel, clazz);\n\t\t\treturn loadOneToMany(entity, clazz, findClass);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * 将entity中的“一对多”的数据填充满\n\t * \n\t * @param entity\n\t * @param clazz\n\t * @param <T>\n\t * @return\n\t */\n\tpublic <T> T loadOneToMany(T entity, Class<T> clazz, Class<?>... findClass) {\n\t\tif (entity != null) {\n\t\t\ttry {\n\t\t\t\tCollection<OneToMany> ones = TableInfo.get(clazz).oneToManyMap\n\t\t\t\t\t\t.values();\n\t\t\t\tObject id = TableInfo.get(clazz).getId().getValue(entity);\n\t\t\t\tfor (OneToMany one : ones) {\n\t\t\t\t\tboolean isFind = false;\n\t\t\t\t\tif (findClass == null || findClass.length == 0) {\n\t\t\t\t\t\tisFind = true;\n\t\t\t\t\t}\n\t\t\t\t\tfor (Class<?> mClass : findClass) {\n\t\t\t\t\t\tif (one.getOneClass() == mClass) {\n\t\t\t\t\t\t\tisFind = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (isFind) {\n\t\t\t\t\t\tList<?> list = findAllByWhere(one.getOneClass(),\n                                one.getColumn() + \"=\" + id);\n\t\t\t\t\t\tif (list != null) {\n\t\t\t\t\t\t\t/* 如果是OneToManyLazyLoader泛型，则执行灌入懒加载数据 */\n\t\t\t\t\t\t\tif (one.getDataType() == OneToManyLazyLoader.class) {\n\t\t\t\t\t\t\t\tOneToManyLazyLoader oneToManyLazyLoader = one\n\t\t\t\t\t\t\t\t\t\t.getValue(entity);\n\t\t\t\t\t\t\t\toneToManyLazyLoader.setList(list);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tone.setValue(entity, list);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn entity;\n\t}\n\n\t/**\n\t * 查找所有的数据\n\t * \n\t * @param clazz\n\t */\n\tpublic <T> List<T> findAll(Class<T> clazz) {\n\t\tcheckTableExist(clazz);\n\t\treturn findAllBySql(clazz, SqlBuilder.getSelectSQL(clazz));\n\t}\n\n\t/**\n\t * 查找所有数据\n\t * \n\t * @param clazz\n\t * @param orderBy\n\t *            排序的字段\n\t */\n\tpublic <T> List<T> findAll(Class<T> clazz, String orderBy) {\n\t\tcheckTableExist(clazz);\n\t\treturn findAllBySql(clazz, SqlBuilder.getSelectSQL(clazz)\n\t\t\t\t+ \" ORDER BY \" + orderBy);\n\t}\n\n\t/**\n\t * 根据条件查找所有数据\n\t * \n\t * @param clazz\n\t * @param strWhere\n\t *            条件为空的时候查找所有数据\n\t */\n\tpublic <T> List<T> findAllByWhere(Class<T> clazz, String strWhere) {\n\t\tcheckTableExist(clazz);\n\t\treturn findAllBySql(clazz,\n\t\t\t\tSqlBuilder.getSelectSQLByWhere(clazz, strWhere));\n\t}\n\n\t/**\n\t * 根据条件查找所有数据\n\t * \n\t * @param clazz\n\t * @param strWhere\n\t *            条件为空的时候查找所有数据\n\t * @param orderBy\n\t *            排序字段\n\t */\n\tpublic <T> List<T> findAllByWhere(Class<T> clazz, String strWhere,\n\t\t\tString orderBy) {\n\t\treturn findAllByWhere(clazz, strWhere, orderBy, false);\n\t}\n\n\tpublic <T> List<T> findAllByWhere(Class<T> clazz, String strWhere,\n\t\t\t\t\t\t\t\t\t  String orderBy, boolean desc) {\n\t\tcheckTableExist(clazz);\n\t\tif (desc){\n\t\t\treturn findAllBySql(clazz,\n\t\t\t\t\tSqlBuilder.getSelectSQLByWhere(clazz, strWhere) + \" ORDER BY \"\n\t\t\t\t\t\t\t+ orderBy + \" DESC\");\n\t\t}else {\n\t\t\treturn findAllBySql(clazz,\n\t\t\t\t\tSqlBuilder.getSelectSQLByWhere(clazz, strWhere) + \" ORDER BY \"\n\t\t\t\t\t\t\t+ orderBy);\n\t\t}\n\n\t}\n\n\t/**\n\t * 根据条件查找所有数据\n\t * \n\t * @param clazz\n\t * @param strSQL\n\t */\n\tprivate <T> List<T> findAllBySql(Class<T> clazz, String strSQL) {\n\t\tcheckTableExist(clazz);\n\t\tdebugSql(strSQL);\n\t\tCursor cursor = db.rawQuery(strSQL, null);\n\t\ttry {\n\t\t\tList<T> list = new ArrayList<T>();\n\t\t\twhile (cursor.moveToNext()) {\n\t\t\t\tT t = CursorUtils.getEntity(cursor, clazz, this);\n\t\t\t\tlist.add(t);\n\t\t\t}\n\t\t\treturn list;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (cursor != null)\n\t\t\t\tcursor.close();\n\t\t\tcursor = null;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql语句查找数据，这个一般用于数据统计\n\t * \n\t * @param strSQL\n\t */\n\tpublic DbModel findDbModelBySQL(String strSQL) {\n\t\tdebugSql(strSQL);\n\t\tCursor cursor = db.rawQuery(strSQL, null);\n\t\ttry {\n\t\t\tif (cursor.moveToNext()) {\n\t\t\t\treturn CursorUtils.getDbModel(cursor);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tcursor.close();\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic List<DbModel> findDbModelListBySQL(String strSQL) {\n\t\tdebugSql(strSQL);\n\t\tCursor cursor = db.rawQuery(strSQL, null);\n\t\tList<DbModel> dbModelList = new ArrayList<DbModel>();\n\t\ttry {\n\t\t\twhile (cursor.moveToNext()) {\n\t\t\t\tdbModelList.add(CursorUtils.getDbModel(cursor));\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tcursor.close();\n\t\t}\n\t\treturn dbModelList;\n\t}\n\n\tprivate void checkTableExist(Class<?> clazz) {\n\t\tif (!tableIsExist(TableInfo.get(clazz))) {\n\t\t\tString sql = SqlBuilder.getCreatTableSQL(clazz);\n\t\t\tdebugSql(sql);\n\t\t\tdb.execSQL(sql);\n\t\t}\n\t}\n\n\tprivate boolean tableIsExist(TableInfo table) {\n\t\tif (table.isCheckDatabese())\n\t\t\treturn true;\n\n\t\tCursor cursor = null;\n\t\ttry {\n\t\t\tString sql = \"SELECT COUNT(*) AS c FROM sqlite_master WHERE type ='table' AND name ='\"\n\t\t\t\t\t+ table.getTableName() + \"' \";\n\t\t\tdebugSql(sql);\n\t\t\tcursor = db.rawQuery(sql, null);\n\t\t\tif (cursor != null && cursor.moveToNext()) {\n\t\t\t\tint count = cursor.getInt(0);\n\t\t\t\tif (count > 0) {\n\t\t\t\t\ttable.setCheckDatabese(true);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (cursor != null)\n\t\t\t\tcursor.close();\n\t\t\tcursor = null;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprivate void debugSql(String sql) {\n\t\tif (config != null && config.isDebug())\n\t\t\tLog.d(\"Debug SQL\", \">>>>>>  \" + sql);\n\t}\n\n\tpublic static class DaoConfig {\n\t\tprivate Context mContext = null; // android上下文\n\t\tprivate String mDbName = \"notes.db\"; // 数据库名字\n\t\tprivate int dbVersion = 1; // 数据库版本\n\t\tprivate boolean debug = true; // 是否是调试模式（调试模式 增删改查的时候显示SQL语句）\n\t\tprivate DbUpdateListener dbUpdateListener;\n\t\t// private boolean saveOnSDCard = false;//是否保存到SD卡\n\t\tprivate String targetDirectory;// 数据库文件在sd卡中的目录\n\n\t\tpublic Context getContext() {\n\t\t\treturn mContext;\n\t\t}\n\n\t\tpublic void setContext(Context context) {\n\t\t\tthis.mContext = context;\n\t\t}\n\n\t\tpublic String getDbName() {\n\t\t\treturn mDbName;\n\t\t}\n\n\t\tpublic void setDbName(String dbName) {\n\t\t\tthis.mDbName = dbName;\n\t\t}\n\n\t\tpublic int getDbVersion() {\n\t\t\treturn dbVersion;\n\t\t}\n\n\t\tpublic void setDbVersion(int dbVersion) {\n\t\t\tthis.dbVersion = dbVersion;\n\t\t}\n\n\t\tpublic boolean isDebug() {\n\t\t\treturn debug;\n\t\t}\n\n\t\tpublic void setDebug(boolean debug) {\n\t\t\tthis.debug = debug;\n\t\t}\n\n\t\tpublic DbUpdateListener getDbUpdateListener() {\n\t\t\treturn dbUpdateListener;\n\t\t}\n\n\t\tpublic void setDbUpdateListener(DbUpdateListener dbUpdateListener) {\n\t\t\tthis.dbUpdateListener = dbUpdateListener;\n\t\t}\n\n\t\t// public boolean isSaveOnSDCard() {\n\t\t// return saveOnSDCard;\n\t\t// }\n\t\t//\n\t\t// public void setSaveOnSDCard(boolean saveOnSDCard) {\n\t\t// this.saveOnSDCard = saveOnSDCard;\n\t\t// }\n\n\t\tpublic String getTargetDirectory() {\n\t\t\treturn targetDirectory;\n\t\t}\n\n\t\tpublic void setTargetDirectory(String targetDirectory) {\n\t\t\tthis.targetDirectory = targetDirectory;\n\t\t}\n\t}\n\n\t/**\n\t * 在SD卡的指定目录上创建文件\n\t * \n\t * @param sdcardPath\n\t * @param dbfilename\n\t * @return\n\t */\n\tprivate SQLiteDatabase createDbFileOnSDCard(String sdcardPath,\n\t\t\tString dbfilename) {\n\t\tFile dbf = new File(sdcardPath, dbfilename);\n\t\tif (!dbf.exists()) {\n\t\t\ttry {\n\t\t\t\tif (dbf.createNewFile()) {\n\t\t\t\t\treturn SQLiteDatabase.openOrCreateDatabase(dbf, null);\n\t\t\t\t}\n\t\t\t} catch (IOException ioex) {\n\t\t\t\tthrow new DbException(\"数据库文件创建失败\", ioex);\n\t\t\t}\n\t\t} else {\n\t\t\treturn SQLiteDatabase.openOrCreateDatabase(dbf, null);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tclass SqliteDbHelper extends SQLiteOpenHelper {\n\n\t\tprivate DbUpdateListener mDbUpdateListener;\n\n\t\tpublic SqliteDbHelper(Context context, String name, int version,\n\t\t\t\tDbUpdateListener dbUpdateListener) {\n\t\t\tsuper(context, name, null, version);\n\t\t\tthis.mDbUpdateListener = dbUpdateListener;\n\t\t}\n\n\t\t@Override\n        public void onCreate(SQLiteDatabase db) {\n\t\t}\n\n\t\t@Override\n        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n\t\t\tif (mDbUpdateListener != null) {\n\t\t\t\tmDbUpdateListener.onUpgrade(db, oldVersion, newVersion);\n\t\t\t} else { // 清空所有的数据信息\n\t\t\t\tdropDb();\n\t\t\t}\n\t\t}\n\n\t}\n\n\tpublic interface DbUpdateListener {\n\t\tpublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);\n\t}\n\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/annotation/sqlite/Id.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.annotation.sqlite;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n/**\n * @title Id主键配置\n * @description 不配置的时候默认找类的id或_id字段作为主键，column不配置的是默认为字段名\n * @author michael Young (www.YangFuhai.com)\n * @version 1.0\n * @created 2012-10-31\n */\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.RUNTIME) \npublic @interface Id {\n\t public String column() default \"\";\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/annotation/sqlite/ManyToOne.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.annotation.sqlite;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.RUNTIME) \npublic @interface ManyToOne {\n\t public String column() default \"\";\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/annotation/sqlite/OneToMany.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.annotation.sqlite;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.RUNTIME) \npublic @interface OneToMany {\n\t\n\t public String manyColumn();\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/annotation/sqlite/Property.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.annotation.sqlite;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.RUNTIME) \npublic @interface Property {\n\t public String column() default \"\";\n\t public String defaultValue() default \"\";\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/annotation/sqlite/Table.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.annotation.sqlite;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME) \npublic @interface  Table {\n\t public String name();\n}"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/annotation/sqlite/Transient.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.annotation.sqlite;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.RUNTIME) \npublic @interface Transient {\n\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/core/AbstractCollection.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 */\npackage net.tsz.afinal.core;\n\nimport java.lang.reflect.Array;\nimport java.util.Collection;\nimport java.util.Iterator;\n\n/**\n * Class {@code AbstractCollection} is an abstract implementation of the {@code\n * Collection} interface. A subclass must implement the abstract methods {@code\n * iterator()} and {@code size()} to create an immutable collection. To create a\n * modifiable collection it's necessary to override the {@code add()} method that\n * currently throws an {@code UnsupportedOperationException}.\n *\n * @since 1.2\n */\npublic abstract class AbstractCollection<E> implements Collection<E> {\n\n    /**\n     * Constructs a new instance of this AbstractCollection.\n     */\n    protected AbstractCollection() {\n    }\n\n    public boolean add(E object) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Attempts to add all of the objects contained in {@code collection}\n     * to the contents of this {@code Collection} (optional). This implementation\n     * iterates over the given {@code Collection} and calls {@code add} for each\n     * element. If any of these calls return {@code true}, then {@code true} is\n     * returned as result of this method call, {@code false} otherwise. If this\n     * {@code Collection} does not support adding elements, an {@code\n     * UnsupportedOperationException} is thrown.\n     * <p>\n     * If the passed {@code Collection} is changed during the process of adding elements\n     * to this {@code Collection}, the behavior depends on the behavior of the passed\n     * {@code Collection}.\n     *\n     * @param collection\n     *            the collection of objects.\n     * @return {@code true} if this {@code Collection} is modified, {@code false}\n     *         otherwise.\n     * @throws UnsupportedOperationException\n     *                if adding to this {@code Collection} is not supported.\n     * @throws ClassCastException\n     *                if the class of an object is inappropriate for this\n     *                {@code Collection}.\n     * @throws IllegalArgumentException\n     *                if an object cannot be added to this {@code Collection}.\n     * @throws NullPointerException\n     *                if {@code collection} is {@code null}, or if it contains\n     *                {@code null} elements and this {@code Collection} does not support\n     *                such elements.\n     */\n    public boolean addAll(Collection<? extends E> collection) {\n        boolean result = false;\n        Iterator<? extends E> it = collection.iterator();\n        while (it.hasNext()) {\n            if (add(it.next())) {\n                result = true;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Removes all elements from this {@code Collection}, leaving it empty (optional).\n     * This implementation iterates over this {@code Collection} and calls the {@code\n     * remove} method on each element. If the iterator does not support removal\n     * of elements, an {@code UnsupportedOperationException} is thrown.\n     * <p>\n     * Concrete implementations usually can clear a {@code Collection} more efficiently\n     * and should therefore overwrite this method.\n     *\n     * @throws UnsupportedOperationException\n     *                it the iterator does not support removing elements from\n     *                this {@code Collection}\n     * @see #iterator\n     * @see #isEmpty\n     * @see #size\n     */\n    public void clear() {\n        Iterator<E> it = iterator();\n        while (it.hasNext()) {\n            it.next();\n            it.remove();\n        }\n    }\n\n    /**\n     * Tests whether this {@code Collection} contains the specified object. This\n     * implementation iterates over this {@code Collection} and tests, whether any\n     * element is equal to the given object. If {@code object != null} then\n     * {@code object.equals(e)} is called for each element {@code e} returned by\n     * the iterator until the element is found. If {@code object == null} then\n     * each element {@code e} returned by the iterator is compared with the test\n     * {@code e == null}.\n     *\n     * @param object\n     *            the object to search for.\n     * @return {@code true} if object is an element of this {@code Collection}, {@code\n     *         false} otherwise.\n     * @throws ClassCastException\n     *                if the object to look for isn't of the correct type.\n     * @throws NullPointerException\n     *                if the object to look for is {@code null} and this\n     *                {@code Collection} doesn't support {@code null} elements.\n     */\n    public boolean contains(Object object) {\n        Iterator<E> it = iterator();\n        if (object != null) {\n            while (it.hasNext()) {\n                if (object.equals(it.next())) {\n                    return true;\n                }\n            }\n        } else {\n            while (it.hasNext()) {\n                if (it.next() == null) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Tests whether this {@code Collection} contains all objects contained in the\n     * specified {@code Collection}. This implementation iterates over the specified\n     * {@code Collection}. If one element returned by the iterator is not contained in\n     * this {@code Collection}, then {@code false} is returned; {@code true} otherwise.\n     *\n     * @param collection\n     *            the collection of objects.\n     * @return {@code true} if all objects in the specified {@code Collection} are\n     *         elements of this {@code Collection}, {@code false} otherwise.\n     * @throws ClassCastException\n     *                if one or more elements of {@code collection} isn't of the\n     *                correct type.\n     * @throws NullPointerException\n     *                if {@code collection} contains at least one {@code null}\n     *                element and this {@code Collection} doesn't support {@code null}\n     *                elements.\n     * @throws NullPointerException\n     *                if {@code collection} is {@code null}.\n     */\n    public boolean containsAll(Collection<?> collection) {\n        Iterator<?> it = collection.iterator();\n        while (it.hasNext()) {\n            if (!contains(it.next())) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Returns if this {@code Collection} contains no elements. This implementation\n     * tests, whether {@code size} returns 0.\n     *\n     * @return {@code true} if this {@code Collection} has no elements, {@code false}\n     *         otherwise.\n     *\n     * @see #size\n     */\n    public boolean isEmpty() {\n        return size() == 0;\n    }\n\n    /**\n     * Returns an instance of {@link Iterator} that may be used to access the\n     * objects contained by this {@code Collection}. The order in which the elements are\n     * returned by the {@link Iterator} is not defined unless the instance of the\n     * {@code Collection} has a defined order.  In that case, the elements are returned in that order.\n     * <p>\n     * In this class this method is declared abstract and has to be implemented\n     * by concrete {@code Collection} implementations.\n     *\n     * @return an iterator for accessing the {@code Collection} contents.\n     */\n    public abstract Iterator<E> iterator();\n\n    /**\n     * Removes one instance of the specified object from this {@code Collection} if one\n     * is contained (optional). This implementation iterates over this\n     * {@code Collection} and tests for each element {@code e} returned by the iterator,\n     * whether {@code e} is equal to the given object. If {@code object != null}\n     * then this test is performed using {@code object.equals(e)}, otherwise\n     * using {@code object == null}. If an element equal to the given object is\n     * found, then the {@code remove} method is called on the iterator and\n     * {@code true} is returned, {@code false} otherwise. If the iterator does\n     * not support removing elements, an {@code UnsupportedOperationException}\n     * is thrown.\n     *\n     * @param object\n     *            the object to remove.\n     * @return {@code true} if this {@code Collection} is modified, {@code false}\n     *         otherwise.\n     * @throws UnsupportedOperationException\n     *                if removing from this {@code Collection} is not supported.\n     * @throws ClassCastException\n     *                if the object passed is not of the correct type.\n     * @throws NullPointerException\n     *                if {@code object} is {@code null} and this {@code Collection}\n     *                doesn't support {@code null} elements.\n     */\n    public boolean remove(Object object) {\n        Iterator<?> it = iterator();\n        if (object != null) {\n            while (it.hasNext()) {\n                if (object.equals(it.next())) {\n                    it.remove();\n                    return true;\n                }\n            }\n        } else {\n            while (it.hasNext()) {\n                if (it.next() == null) {\n                    it.remove();\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Removes all occurrences in this {@code Collection} of each object in the\n     * specified {@code Collection} (optional). After this method returns none of the\n     * elements in the passed {@code Collection} can be found in this {@code Collection}\n     * anymore.\n     * <p>\n     * This implementation iterates over this {@code Collection} and tests for each\n     * element {@code e} returned by the iterator, whether it is contained in\n     * the specified {@code Collection}. If this test is positive, then the {@code\n     * remove} method is called on the iterator. If the iterator does not\n     * support removing elements, an {@code UnsupportedOperationException} is\n     * thrown.\n     *\n     * @param collection\n     *            the collection of objects to remove.\n     * @return {@code true} if this {@code Collection} is modified, {@code false}\n     *         otherwise.\n     * @throws UnsupportedOperationException\n     *                if removing from this {@code Collection} is not supported.\n     * @throws ClassCastException\n     *                if one or more elements of {@code collection} isn't of the\n     *                correct type.\n     * @throws NullPointerException\n     *                if {@code collection} contains at least one {@code null}\n     *                element and this {@code Collection} doesn't support {@code null}\n     *                elements.\n     * @throws NullPointerException\n     *                if {@code collection} is {@code null}.\n     */\n    public boolean removeAll(Collection<?> collection) {\n        boolean result = false;\n        Iterator<?> it = iterator();\n        while (it.hasNext()) {\n            if (collection.contains(it.next())) {\n                it.remove();\n                result = true;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Removes all objects from this {@code Collection} that are not also found in the\n     * {@code Collection} passed (optional). After this method returns this {@code Collection}\n     * will only contain elements that also can be found in the {@code Collection}\n     * passed to this method.\n     * <p>\n     * This implementation iterates over this {@code Collection} and tests for each\n     * element {@code e} returned by the iterator, whether it is contained in\n     * the specified {@code Collection}. If this test is negative, then the {@code\n     * remove} method is called on the iterator. If the iterator does not\n     * support removing elements, an {@code UnsupportedOperationException} is\n     * thrown.\n     *\n     * @param collection\n     *            the collection of objects to retain.\n     * @return {@code true} if this {@code Collection} is modified, {@code false}\n     *         otherwise.\n     * @throws UnsupportedOperationException\n     *                if removing from this {@code Collection} is not supported.\n     * @throws ClassCastException\n     *                if one or more elements of {@code collection}\n     *                isn't of the correct type.\n     * @throws NullPointerException\n     *                if {@code collection} contains at least one\n     *                {@code null} element and this {@code Collection} doesn't support\n     *                {@code null} elements.\n     * @throws NullPointerException\n     *                if {@code collection} is {@code null}.\n     */\n    public boolean retainAll(Collection<?> collection) {\n        boolean result = false;\n        Iterator<?> it = iterator();\n        while (it.hasNext()) {\n            if (!collection.contains(it.next())) {\n                it.remove();\n                result = true;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Returns a count of how many objects this {@code Collection} contains.\n     * <p>\n     * In this class this method is declared abstract and has to be implemented\n     * by concrete {@code Collection} implementations.\n     *\n     * @return how many objects this {@code Collection} contains, or {@code Integer.MAX_VALUE}\n     *         if there are more than {@code Integer.MAX_VALUE} elements in this\n     *         {@code Collection}.\n     */\n    public abstract int size();\n\n    public Object[] toArray() {\n        int size = size(), index = 0;\n        Iterator<?> it = iterator();\n        Object[] array = new Object[size];\n        while (index < size) {\n            array[index++] = it.next();\n        }\n        return array;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> T[] toArray(T[] contents) {\n        int size = size(), index = 0;\n        if (size > contents.length) {\n            Class<?> ct = contents.getClass().getComponentType();\n            contents = (T[]) Array.newInstance(ct, size);\n        }\n        for (E entry : this) {\n            contents[index++] = (T) entry;\n        }\n        if (index < contents.length) {\n            contents[index] = null;\n        }\n        return contents;\n    }\n\n    /**\n     * Returns the string representation of this {@code Collection}. The presentation\n     * has a specific format. It is enclosed by square brackets (\"[]\"). Elements\n     * are separated by ', ' (comma and space).\n     *\n     * @return the string representation of this {@code Collection}.\n     */\n    @Override\n    public String toString() {\n        if (isEmpty()) {\n            return \"[]\";\n        }\n\n        StringBuilder buffer = new StringBuilder(size() * 16);\n        buffer.append('[');\n        Iterator<?> it = iterator();\n        while (it.hasNext()) {\n            Object next = it.next();\n            if (next != this) {\n                buffer.append(next);\n            } else {\n                buffer.append(\"(this Collection)\");\n            }\n            if (it.hasNext()) {\n                buffer.append(\", \");\n            }\n        }\n        buffer.append(']');\n        return buffer.toString();\n    }\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/core/ArrayDeque.java",
    "content": "/*\n * Written by Josh Bloch of Google Inc. and released to the public domain,\n * as explained at http://creativecommons.org/licenses/publicdomain.\n */\n\npackage net.tsz.afinal.core;\n\n// BEGIN android-note\n// removed link to collections framework docs\n// END android-note\n\nimport java.io.*;\nimport java.util.Collection;\nimport java.util.ConcurrentModificationException;\nimport java.util.Iterator;\nimport java.util.NoSuchElementException;\n\n/**\n * Resizable-array implementation of the {@link Deque} interface.  Array\n * deques have no capacity restrictions; they grow as necessary to support\n * usage.  They are not thread-safe; in the absence of external\n * synchronization, they do not support concurrent access by multiple threads.\n * Null elements are prohibited.  This class is likely to be faster than\n * {@link Stack} when used as a stack, and faster than {@link LinkedList}\n * when used as a queue.\n *\n * <p>Most <tt>ArrayDeque</tt> operations run in amortized constant time.\n * Exceptions include {@link #remove(Object) remove}, {@link\n * #removeFirstOccurrence removeFirstOccurrence}, {@link #removeLastOccurrence\n * removeLastOccurrence}, {@link #contains contains}, {@link #iterator\n * iterator.remove()}, and the bulk operations, all of which run in linear\n * time.\n *\n * <p>The iterators returned by this class's <tt>iterator</tt> method are\n * <i>fail-fast</i>: If the deque is modified at any time after the iterator\n * is created, in any way except through the iterator's own <tt>remove</tt>\n * method, the iterator will generally throw a {@link\n * ConcurrentModificationException}.  Thus, in the face of concurrent\n * modification, the iterator fails quickly and cleanly, rather than risking\n * arbitrary, non-deterministic behavior at an undetermined time in the\n * future.\n *\n * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed\n * as it is, generally speaking, impossible to make any hard guarantees in the\n * presence of unsynchronized concurrent modification.  Fail-fast iterators\n * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.\n * Therefore, it would be wrong to write a program that depended on this\n * exception for its correctness: <i>the fail-fast behavior of iterators\n * should be used only to detect bugs.</i>\n *\n * <p>This class and its iterator implement all of the\n * <em>optional</em> methods of the {@link Collection} and {@link\n * Iterator} interfaces.\n *\n * @author  Josh Bloch and Doug Lea\n * @since   1.6\n * @param <E> the type of elements held in this collection\n */\npublic class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable\n{\n    /**\n     * The array in which the elements of the deque are stored.\n     * The capacity of the deque is the length of this array, which is\n     * always a power of two. The array is never allowed to become\n     * full, except transiently within an addX method where it is\n     * resized (see doubleCapacity) immediately upon becoming full,\n     * thus avoiding head and tail wrapping around to equal each\n     * other.  We also guarantee that all array cells not holding\n     * deque elements are always null.\n     */\n    private transient E[] elements;\n\n    /**\n     * The index of the element at the head of the deque (which is the\n     * element that would be removed by remove() or pop()); or an\n     * arbitrary number equal to tail if the deque is empty.\n     */\n    private transient int head;\n\n    /**\n     * The index at which the next element would be added to the tail\n     * of the deque (via addLast(E), add(E), or push(E)).\n     */\n    private transient int tail;\n\n    /**\n     * The minimum capacity that we'll use for a newly created deque.\n     * Must be a power of 2.\n     */\n    private static final int MIN_INITIAL_CAPACITY = 8;\n\n    // ******  Array allocation and resizing utilities ******\n\n    /**\n     * Allocate empty array to hold the given number of elements.\n     *\n     * @param numElements  the number of elements to hold\n     */\n    @SuppressWarnings(\"unchecked\")\n\tprivate void allocateElements(int numElements) {\n        int initialCapacity = MIN_INITIAL_CAPACITY;\n        // Find the best power of two to hold elements.\n        // Tests \"<=\" because arrays aren't kept full.\n        if (numElements >= initialCapacity) {\n            initialCapacity = numElements;\n            initialCapacity |= (initialCapacity >>>  1);\n            initialCapacity |= (initialCapacity >>>  2);\n            initialCapacity |= (initialCapacity >>>  4);\n            initialCapacity |= (initialCapacity >>>  8);\n            initialCapacity |= (initialCapacity >>> 16);\n            initialCapacity++;\n\n            if (initialCapacity < 0)   // Too many elements, must back off\n                initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements\n        }\n        elements = (E[]) new Object[initialCapacity];\n    }\n\n    /**\n     * Double the capacity of this deque.  Call only when full, i.e.,\n     * when head and tail have wrapped around to become equal.\n     */\n    @SuppressWarnings(\"unchecked\")\n\tprivate void doubleCapacity() {\n        assert head == tail;\n        int p = head;\n        int n = elements.length;\n        int r = n - p; // number of elements to the right of p\n        int newCapacity = n << 1;\n        if (newCapacity < 0)\n            throw new IllegalStateException(\"Sorry, deque too big\");\n        Object[] a = new Object[newCapacity];\n        System.arraycopy(elements, p, a, 0, r);\n        System.arraycopy(elements, 0, a, r, p);\n        elements = (E[])a;\n        head = 0;\n        tail = n;\n    }\n\n    /**\n     * Copies the elements from our element array into the specified array,\n     * in order (from first to last element in the deque).  It is assumed\n     * that the array is large enough to hold all elements in the deque.\n     *\n     * @return its argument\n     */\n    private <T> T[] copyElements(T[] a) {\n        if (head < tail) {\n            System.arraycopy(elements, head, a, 0, size());\n        } else if (head > tail) {\n            int headPortionLen = elements.length - head;\n            System.arraycopy(elements, head, a, 0, headPortionLen);\n            System.arraycopy(elements, 0, a, headPortionLen, tail);\n        }\n        return a;\n    }\n\n    /**\n     * Constructs an empty array deque with an initial capacity\n     * sufficient to hold 16 elements.\n     */\n    @SuppressWarnings(\"unchecked\")\n\tpublic ArrayDeque() {\n        elements = (E[]) new Object[16];\n    }\n\n    /**\n     * Constructs an empty array deque with an initial capacity\n     * sufficient to hold the specified number of elements.\n     *\n     * @param numElements  lower bound on initial capacity of the deque\n     */\n    public ArrayDeque(int numElements) {\n        allocateElements(numElements);\n    }\n\n    /**\n     * Constructs a deque containing the elements of the specified\n     * collection, in the order they are returned by the collection's\n     * iterator.  (The first element returned by the collection's\n     * iterator becomes the first element, or <i>front</i> of the\n     * deque.)\n     *\n     * @param c the collection whose elements are to be placed into the deque\n     * @throws NullPointerException if the specified collection is null\n     */\n    public ArrayDeque(Collection<? extends E> c) {\n        allocateElements(c.size());\n        addAll(c);\n    }\n\n    // The main insertion and extraction methods are addFirst,\n    // addLast, pollFirst, pollLast. The other methods are defined in\n    // terms of these.\n\n    /**\n     * Inserts the specified element at the front of this deque.\n     *\n     * @param e the element to add\n     * @throws NullPointerException if the specified element is null\n     */\n    public void addFirst(E e) {\n        if (e == null)\n            throw new NullPointerException();\n        elements[head = (head - 1) & (elements.length - 1)] = e;\n        if (head == tail)\n            doubleCapacity();\n    }\n\n    /**\n     * Inserts the specified element at the end of this deque.\n     *\n     * <p>This method is equivalent to {@link #add}.\n     *\n     * @param e the element to add\n     * @throws NullPointerException if the specified element is null\n     */\n    public void addLast(E e) {\n        if (e == null)\n            throw new NullPointerException();\n        elements[tail] = e;\n        if ( (tail = (tail + 1) & (elements.length - 1)) == head)\n            doubleCapacity();\n    }\n\n    /**\n     * Inserts the specified element at the front of this deque.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> (as specified by {@link Deque#offerFirst})\n     * @throws NullPointerException if the specified element is null\n     */\n    public boolean offerFirst(E e) {\n        addFirst(e);\n        return true;\n    }\n\n    /**\n     * Inserts the specified element at the end of this deque.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> (as specified by {@link Deque#offerLast})\n     * @throws NullPointerException if the specified element is null\n     */\n    public boolean offerLast(E e) {\n        addLast(e);\n        return true;\n    }\n\n    /**\n     * @throws NoSuchElementException {@inheritDoc}\n     */\n    public E removeFirst() {\n        E x = pollFirst();\n        if (x == null)\n            throw new NoSuchElementException();\n        return x;\n    }\n\n    /**\n     * @throws NoSuchElementException {@inheritDoc}\n     */\n    public E removeLast() {\n        E x = pollLast();\n        if (x == null)\n            throw new NoSuchElementException();\n        return x;\n    }\n\n    public E pollFirst() {\n        int h = head;\n        E result = elements[h]; // Element is null if deque empty\n        if (result == null)\n            return null;\n        elements[h] = null;     // Must null out slot\n        head = (h + 1) & (elements.length - 1);\n        return result;\n    }\n\n    public E pollLast() {\n        int t = (tail - 1) & (elements.length - 1);\n        E result = elements[t];\n        if (result == null)\n            return null;\n        elements[t] = null;\n        tail = t;\n        return result;\n    }\n\n    /**\n     * @throws NoSuchElementException {@inheritDoc}\n     */\n    public E getFirst() {\n        E x = elements[head];\n        if (x == null)\n            throw new NoSuchElementException();\n        return x;\n    }\n\n    /**\n     * @throws NoSuchElementException {@inheritDoc}\n     */\n    public E getLast() {\n        E x = elements[(tail - 1) & (elements.length - 1)];\n        if (x == null)\n            throw new NoSuchElementException();\n        return x;\n    }\n\n    public E peekFirst() {\n        return elements[head]; // elements[head] is null if deque empty\n    }\n\n    public E peekLast() {\n        return elements[(tail - 1) & (elements.length - 1)];\n    }\n\n    /**\n     * Removes the first occurrence of the specified element in this\n     * deque (when traversing the deque from head to tail).\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the first element <tt>e</tt> such that\n     * <tt>o.equals(e)</tt> (if such an element exists).\n     * Returns <tt>true</tt> if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     *\n     * @param o element to be removed from this deque, if present\n     * @return <tt>true</tt> if the deque contained the specified element\n     */\n    public boolean removeFirstOccurrence(Object o) {\n        if (o == null)\n            return false;\n        int mask = elements.length - 1;\n        int i = head;\n        E x;\n        while ( (x = elements[i]) != null) {\n            if (o.equals(x)) {\n                delete(i);\n                return true;\n            }\n            i = (i + 1) & mask;\n        }\n        return false;\n    }\n\n    /**\n     * Removes the last occurrence of the specified element in this\n     * deque (when traversing the deque from head to tail).\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the last element <tt>e</tt> such that\n     * <tt>o.equals(e)</tt> (if such an element exists).\n     * Returns <tt>true</tt> if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     *\n     * @param o element to be removed from this deque, if present\n     * @return <tt>true</tt> if the deque contained the specified element\n     */\n    public boolean removeLastOccurrence(Object o) {\n        if (o == null)\n            return false;\n        int mask = elements.length - 1;\n        int i = (tail - 1) & mask;\n        E x;\n        while ( (x = elements[i]) != null) {\n            if (o.equals(x)) {\n                delete(i);\n                return true;\n            }\n            i = (i - 1) & mask;\n        }\n        return false;\n    }\n\n    // *** Queue methods ***\n\n    /**\n     * Inserts the specified element at the end of this deque.\n     *\n     * <p>This method is equivalent to {@link #addLast}.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> (as specified by {@link Collection#add})\n     * @throws NullPointerException if the specified element is null\n     */\n    public boolean add(E e) {\n        addLast(e);\n        return true;\n    }\n\n    /**\n     * Inserts the specified element at the end of this deque.\n     *\n     * <p>This method is equivalent to {@link #offerLast}.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> (as specified by {@link Queue#offer})\n     * @throws NullPointerException if the specified element is null\n     */\n    public boolean offer(E e) {\n        return offerLast(e);\n    }\n\n    /**\n     * Retrieves and removes the head of the queue represented by this deque.\n     *\n     * This method differs from {@link #poll poll} only in that it throws an\n     * exception if this deque is empty.\n     *\n     * <p>This method is equivalent to {@link #removeFirst}.\n     *\n     * @return the head of the queue represented by this deque\n     * @throws NoSuchElementException {@inheritDoc}\n     */\n    public E remove() {\n        return removeFirst();\n    }\n\n    /**\n     * Retrieves and removes the head of the queue represented by this deque\n     * (in other words, the first element of this deque), or returns\n     * <tt>null</tt> if this deque is empty.\n     *\n     * <p>This method is equivalent to {@link #pollFirst}.\n     *\n     * @return the head of the queue represented by this deque, or\n     *         <tt>null</tt> if this deque is empty\n     */\n    public E poll() {\n        return pollFirst();\n    }\n\n    /**\n     * Retrieves, but does not remove, the head of the queue represented by\n     * this deque.  This method differs from {@link #peek peek} only in\n     * that it throws an exception if this deque is empty.\n     *\n     * <p>This method is equivalent to {@link #getFirst}.\n     *\n     * @return the head of the queue represented by this deque\n     * @throws NoSuchElementException {@inheritDoc}\n     */\n    public E element() {\n        return getFirst();\n    }\n\n    /**\n     * Retrieves, but does not remove, the head of the queue represented by\n     * this deque, or returns <tt>null</tt> if this deque is empty.\n     *\n     * <p>This method is equivalent to {@link #peekFirst}.\n     *\n     * @return the head of the queue represented by this deque, or\n     *         <tt>null</tt> if this deque is empty\n     */\n    public E peek() {\n        return peekFirst();\n    }\n\n    // *** Stack methods ***\n\n    /**\n     * Pushes an element onto the stack represented by this deque.  In other\n     * words, inserts the element at the front of this deque.\n     *\n     * <p>This method is equivalent to {@link #addFirst}.\n     *\n     * @param e the element to push\n     * @throws NullPointerException if the specified element is null\n     */\n    public void push(E e) {\n        addFirst(e);\n    }\n\n    /**\n     * Pops an element from the stack represented by this deque.  In other\n     * words, removes and returns the first element of this deque.\n     *\n     * <p>This method is equivalent to {@link #removeFirst()}.\n     *\n     * @return the element at the front of this deque (which is the top\n     *         of the stack represented by this deque)\n     * @throws NoSuchElementException {@inheritDoc}\n     */\n    public E pop() {\n        return removeFirst();\n    }\n\n    private void checkInvariants() {\n        assert elements[tail] == null;\n        assert head == tail ? elements[head] == null :\n            (elements[head] != null &&\n             elements[(tail - 1) & (elements.length - 1)] != null);\n        assert elements[(head - 1) & (elements.length - 1)] == null;\n    }\n\n    /**\n     * Removes the element at the specified position in the elements array,\n     * adjusting head and tail as necessary.  This can result in motion of\n     * elements backwards or forwards in the array.\n     *\n     * <p>This method is called delete rather than remove to emphasize\n     * that its semantics differ from those of {@link List#remove(int)}.\n     *\n     * @return true if elements moved backwards\n     */\n    private boolean delete(int i) {\n        checkInvariants();\n        final E[] elements = this.elements;\n        final int mask = elements.length - 1;\n        final int h = head;\n        final int t = tail;\n        final int front = (i - h) & mask;\n        final int back  = (t - i) & mask;\n\n        // Invariant: head <= i < tail mod circularity\n        if (front >= ((t - h) & mask))\n            throw new ConcurrentModificationException();\n\n        // Optimize for least element motion\n        if (front < back) {\n            if (h <= i) {\n                System.arraycopy(elements, h, elements, h + 1, front);\n            } else { // Wrap around\n                System.arraycopy(elements, 0, elements, 1, i);\n                elements[0] = elements[mask];\n                System.arraycopy(elements, h, elements, h + 1, mask - h);\n            }\n            elements[h] = null;\n            head = (h + 1) & mask;\n            return false;\n        } else {\n            if (i < t) { // Copy the null tail as well\n                System.arraycopy(elements, i + 1, elements, i, back);\n                tail = t - 1;\n            } else { // Wrap around\n                System.arraycopy(elements, i + 1, elements, i, mask - i);\n                elements[mask] = elements[0];\n                System.arraycopy(elements, 1, elements, 0, t);\n                tail = (t - 1) & mask;\n            }\n            return true;\n        }\n    }\n\n    // *** Collection Methods ***\n\n    /**\n     * Returns the number of elements in this deque.\n     *\n     * @return the number of elements in this deque\n     */\n    public int size() {\n        return (tail - head) & (elements.length - 1);\n    }\n\n    /**\n     * Returns <tt>true</tt> if this deque contains no elements.\n     *\n     * @return <tt>true</tt> if this deque contains no elements\n     */\n    public boolean isEmpty() {\n        return head == tail;\n    }\n\n    /**\n     * Returns an iterator over the elements in this deque.  The elements\n     * will be ordered from first (head) to last (tail).  This is the same\n     * order that elements would be dequeued (via successive calls to\n     * {@link #remove} or popped (via successive calls to {@link #pop}).\n     *\n     * @return an iterator over the elements in this deque\n     */\n    public Iterator<E> iterator() {\n        return new DeqIterator();\n    }\n\n    public Iterator<E> descendingIterator() {\n        return new DescendingIterator();\n    }\n\n    private class DeqIterator implements Iterator<E> {\n        /**\n         * Index of element to be returned by subsequent call to next.\n         */\n        private int cursor = head;\n\n        /**\n         * Tail recorded at construction (also in remove), to stop\n         * iterator and also to check for comodification.\n         */\n        private int fence = tail;\n\n        /**\n         * Index of element returned by most recent call to next.\n         * Reset to -1 if element is deleted by a call to remove.\n         */\n        private int lastRet = -1;\n\n        public boolean hasNext() {\n            return cursor != fence;\n        }\n\n        public E next() {\n            if (cursor == fence)\n                throw new NoSuchElementException();\n            E result = elements[cursor];\n            // This check doesn't catch all possible comodifications,\n            // but does catch the ones that corrupt traversal\n            if (tail != fence || result == null)\n                throw new ConcurrentModificationException();\n            lastRet = cursor;\n            cursor = (cursor + 1) & (elements.length - 1);\n            return result;\n        }\n\n        public void remove() {\n            if (lastRet < 0)\n                throw new IllegalStateException();\n            if (delete(lastRet)) { // if left-shifted, undo increment in next()\n                cursor = (cursor - 1) & (elements.length - 1);\n                fence = tail;\n            }\n            lastRet = -1;\n        }\n    }\n\n    private class DescendingIterator implements Iterator<E> {\n        /*\n         * This class is nearly a mirror-image of DeqIterator, using\n         * tail instead of head for initial cursor, and head instead of\n         * tail for fence.\n         */\n        private int cursor = tail;\n        private int fence = head;\n        private int lastRet = -1;\n\n        public boolean hasNext() {\n            return cursor != fence;\n        }\n\n        public E next() {\n            if (cursor == fence)\n                throw new NoSuchElementException();\n            cursor = (cursor - 1) & (elements.length - 1);\n            E result = elements[cursor];\n            if (head != fence || result == null)\n                throw new ConcurrentModificationException();\n            lastRet = cursor;\n            return result;\n        }\n\n        public void remove() {\n            if (lastRet < 0)\n                throw new IllegalStateException();\n            if (!delete(lastRet)) {\n                cursor = (cursor + 1) & (elements.length - 1);\n                fence = head;\n            }\n            lastRet = -1;\n        }\n    }\n\n    /**\n     * Returns <tt>true</tt> if this deque contains the specified element.\n     * More formally, returns <tt>true</tt> if and only if this deque contains\n     * at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>.\n     *\n     * @param o object to be checked for containment in this deque\n     * @return <tt>true</tt> if this deque contains the specified element\n     */\n    public boolean contains(Object o) {\n        if (o == null)\n            return false;\n        int mask = elements.length - 1;\n        int i = head;\n        E x;\n        while ( (x = elements[i]) != null) {\n            if (o.equals(x))\n                return true;\n            i = (i + 1) & mask;\n        }\n        return false;\n    }\n\n    /**\n     * Removes a single instance of the specified element from this deque.\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the first element <tt>e</tt> such that\n     * <tt>o.equals(e)</tt> (if such an element exists).\n     * Returns <tt>true</tt> if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     *\n     * <p>This method is equivalent to {@link #removeFirstOccurrence}.\n     *\n     * @param o element to be removed from this deque, if present\n     * @return <tt>true</tt> if this deque contained the specified element\n     */\n    public boolean remove(Object o) {\n        return removeFirstOccurrence(o);\n    }\n\n    /**\n     * Removes all of the elements from this deque.\n     * The deque will be empty after this call returns.\n     */\n    public void clear() {\n        int h = head;\n        int t = tail;\n        if (h != t) { // clear all cells\n            head = tail = 0;\n            int i = h;\n            int mask = elements.length - 1;\n            do {\n                elements[i] = null;\n                i = (i + 1) & mask;\n            } while (i != t);\n        }\n    }\n\n    /**\n     * Returns an array containing all of the elements in this deque\n     * in proper sequence (from first to last element).\n     *\n     * <p>The returned array will be \"safe\" in that no references to it are\n     * maintained by this deque.  (In other words, this method must allocate\n     * a new array).  The caller is thus free to modify the returned array.\n     *\n     * <p>This method acts as bridge between array-based and collection-based\n     * APIs.\n     *\n     * @return an array containing all of the elements in this deque\n     */\n    public Object[] toArray() {\n        return copyElements(new Object[size()]);\n    }\n\n    /**\n     * Returns an array containing all of the elements in this deque in\n     * proper sequence (from first to last element); the runtime type of the\n     * returned array is that of the specified array.  If the deque fits in\n     * the specified array, it is returned therein.  Otherwise, a new array\n     * is allocated with the runtime type of the specified array and the\n     * size of this deque.\n     *\n     * <p>If this deque fits in the specified array with room to spare\n     * (i.e., the array has more elements than this deque), the element in\n     * the array immediately following the end of the deque is set to\n     * <tt>null</tt>.\n     *\n     * <p>Like the {@link #toArray()} method, this method acts as bridge between\n     * array-based and collection-based APIs.  Further, this method allows\n     * precise control over the runtime type of the output array, and may,\n     * under certain circumstances, be used to save allocation costs.\n     *\n     * <p>Suppose <tt>x</tt> is a deque known to contain only strings.\n     * The following code can be used to dump the deque into a newly\n     * allocated array of <tt>String</tt>:\n     *\n     * <pre>\n     *     String[] y = x.toArray(new String[0]);</pre>\n     *\n     * Note that <tt>toArray(new Object[0])</tt> is identical in function to\n     * <tt>toArray()</tt>.\n     *\n     * @param a the array into which the elements of the deque are to\n     *          be stored, if it is big enough; otherwise, a new array of the\n     *          same runtime type is allocated for this purpose\n     * @return an array containing all of the elements in this deque\n     * @throws ArrayStoreException if the runtime type of the specified array\n     *         is not a supertype of the runtime type of every element in\n     *         this deque\n     * @throws NullPointerException if the specified array is null\n     */\n    @SuppressWarnings(\"unchecked\")\n\tpublic <T> T[] toArray(T[] a) {\n        int size = size();\n        if (a.length < size)\n            a = (T[])java.lang.reflect.Array.newInstance(\n                    a.getClass().getComponentType(), size);\n        copyElements(a);\n        if (a.length > size)\n            a[size] = null;\n        return a;\n    }\n\n    // *** Object methods ***\n\n    /**\n     * Returns a copy of this deque.\n     *\n     * @return a copy of this deque\n     */\n    public ArrayDeque<E> clone() {\n        try {\n            @SuppressWarnings(\"unchecked\")\n\t\t\tArrayDeque<E> result = (ArrayDeque<E>) super.clone();\n            result.elements = Arrays.copyOf(elements, elements.length);\n            return result;\n\n        } catch (CloneNotSupportedException e) {\n            throw new AssertionError();\n        }\n    }\n\n    /**\n     * Appease the serialization gods.\n     */\n    private static final long serialVersionUID = 2340985798034038923L;\n\n    /**\n     * Serialize this deque.\n     *\n     * @serialData The current size (<tt>int</tt>) of the deque,\n     * followed by all of its elements (each an object reference) in\n     * first-to-last order.\n     */\n    private void writeObject(ObjectOutputStream s) throws IOException {\n        s.defaultWriteObject();\n\n        // Write out size\n        s.writeInt(size());\n\n        // Write out elements in order.\n        int mask = elements.length - 1;\n        for (int i = head; i != tail; i = (i + 1) & mask)\n            s.writeObject(elements[i]);\n    }\n\n    /**\n     * Deserialize this deque.\n     */\n    @SuppressWarnings(\"unchecked\")\n\tprivate void readObject(ObjectInputStream s)\n            throws IOException, ClassNotFoundException {\n        s.defaultReadObject();\n\n        // Read in size and allocate array\n        int size = s.readInt();\n        allocateElements(size);\n        head = 0;\n        tail = size;\n\n        // Read in all elements in the proper order.\n        for (int i = 0; i < size; i++)\n            elements[i] = (E)s.readObject();\n    }\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/core/Arrays.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 net.tsz.afinal.core;\n\nimport java.io.Serializable;\nimport java.lang.reflect.Array;\nimport java.util.AbstractList;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.RandomAccess;\n\n/**\n * {@code Arrays} contains static methods which operate on arrays.\n *\n * @since 1.2\n */\npublic class Arrays {\n    private static class ArrayList<E> extends AbstractList<E> implements\n            List<E>, Serializable, RandomAccess {\n\n        private static final long serialVersionUID = -2764017481108945198L;\n\n        private final E[] a;\n\n        ArrayList(E[] storage) {\n            if (storage == null) {\n                throw new NullPointerException();\n            }\n            a = storage;\n        }\n\n        @Override\n        public boolean contains(Object object) {\n            if (object != null) {\n                for (E element : a) {\n                    if (object.equals(element)) {\n                        return true;\n                    }\n                }\n            } else {\n                for (E element : a) {\n                    if (element == null) {\n                        return true;\n                    }\n                }\n            }\n            return false;\n        }\n\n        @Override\n        public E get(int location) {\n            try {\n                return a[location];\n            } catch (ArrayIndexOutOfBoundsException e) {\n//                throw java.util.ArrayList.throwIndexOutOfBoundsException(location, a.length);\n            \tthrow e;\n            }\n        }\n\n        @Override\n        public int indexOf(Object object) {\n            if (object != null) {\n                for (int i = 0; i < a.length; i++) {\n                    if (object.equals(a[i])) {\n                        return i;\n                    }\n                }\n            } else {\n                for (int i = 0; i < a.length; i++) {\n                    if (a[i] == null) {\n                        return i;\n                    }\n                }\n            }\n            return -1;\n        }\n\n        @Override\n        public int lastIndexOf(Object object) {\n            if (object != null) {\n                for (int i = a.length - 1; i >= 0; i--) {\n                    if (object.equals(a[i])) {\n                        return i;\n                    }\n                }\n            } else {\n                for (int i = a.length - 1; i >= 0; i--) {\n                    if (a[i] == null) {\n                        return i;\n                    }\n                }\n            }\n            return -1;\n        }\n\n        @Override\n        public E set(int location, E object) {\n            E result = a[location];\n            a[location] = object;\n            return result;\n        }\n\n        @Override\n        public int size() {\n            return a.length;\n        }\n\n        @Override\n        public Object[] toArray() {\n            return a.clone();\n        }\n\n        @SuppressWarnings(\"unchecked\")\n\t\t@Override\n        public <T> T[] toArray(T[] contents) {\n            int size = size();\n            if (size > contents.length) {\n                Class<?> ct = contents.getClass().getComponentType();\n                contents = (T[]) Array.newInstance(ct, size);\n            }\n            System.arraycopy(a, 0, contents, 0, size);\n            if (size < contents.length) {\n                contents[size] = null;\n            }\n            return contents;\n        }\n    }\n\n    private Arrays() {\n        /* empty */\n    }\n\n    /**\n     * Returns a {@code List} of the objects in the specified array. The size of the\n     * {@code List} cannot be modified, i.e. adding and removing are unsupported, but\n     * the elements can be set. Setting an element modifies the underlying\n     * array.\n     *\n     * @param array\n     *            the array.\n     * @return a {@code List} of the elements of the specified array.\n     */\n    public static <T> List<T> asList(T... array) {\n        return new ArrayList<T>(array);\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array}.\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     */\n    public static int binarySearch(byte[] array, byte value) {\n        return binarySearch(array, 0, array.length, value);\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array},\n     * in the range specified by fromIndex (inclusive) and toIndex (exclusive).\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param startIndex the inclusive start index.\n     * @param endIndex the exclusive start index.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     * @throws IllegalArgumentException if {@code startIndex > endIndex}\n     * @throws ArrayIndexOutOfBoundsException if {@code startIndex < 0 || endIndex > array.length}\n     * @since 1.6\n     */\n    public static int binarySearch(byte[] array, int startIndex, int endIndex, byte value) {\n        checkBinarySearchBounds(startIndex, endIndex, array.length);\n        int lo = startIndex;\n        int hi = endIndex - 1;\n\n        while (lo <= hi) {\n            int mid = (lo + hi) >>> 1;\n            byte midVal = array[mid];\n\n            if (midVal < value) {\n                lo = mid + 1;\n            } else if (midVal > value) {\n                hi = mid - 1;\n            } else {\n                return mid;  // value found\n            }\n        }\n        return ~lo;  // value not present\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array}.\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     */\n    public static int binarySearch(char[] array, char value) {\n        return binarySearch(array, 0, array.length, value);\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array},\n     * in the range specified by fromIndex (inclusive) and toIndex (exclusive).\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param startIndex the inclusive start index.\n     * @param endIndex the exclusive start index.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     * @throws IllegalArgumentException if {@code startIndex > endIndex}\n     * @throws ArrayIndexOutOfBoundsException if {@code startIndex < 0 || endIndex > array.length}\n     * @since 1.6\n     */\n    public static int binarySearch(char[] array, int startIndex, int endIndex, char value) {\n        checkBinarySearchBounds(startIndex, endIndex, array.length);\n        int lo = startIndex;\n        int hi = endIndex - 1;\n\n        while (lo <= hi) {\n            int mid = (lo + hi) >>> 1;\n            char midVal = array[mid];\n\n            if (midVal < value) {\n                lo = mid + 1;\n            } else if (midVal > value) {\n                hi = mid - 1;\n            } else {\n                return mid;  // value found\n            }\n        }\n        return ~lo;  // value not present\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array}.\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     */\n    public static int binarySearch(double[] array, double value) {\n        return binarySearch(array, 0, array.length, value);\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array},\n     * in the range specified by fromIndex (inclusive) and toIndex (exclusive).\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param startIndex the inclusive start index.\n     * @param endIndex the exclusive start index.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     * @throws IllegalArgumentException if {@code startIndex > endIndex}\n     * @throws ArrayIndexOutOfBoundsException if {@code startIndex < 0 || endIndex > array.length}\n     * @since 1.6\n     */\n    public static int binarySearch(double[] array, int startIndex, int endIndex, double value) {\n        checkBinarySearchBounds(startIndex, endIndex, array.length);\n        int lo = startIndex;\n        int hi = endIndex - 1;\n\n        while (lo <= hi) {\n            int mid = (lo + hi) >>> 1;\n            double midVal = array[mid];\n\n            if (midVal < value) {\n                lo = mid + 1;\n            } else if (midVal > value) {\n                hi = mid - 1;\n            } else if (midVal != 0 && midVal == value) {\n                return mid;  // value found\n            } else { // Either midVal and value are == 0 or at least one is NaN\n                long midValBits = Double.doubleToLongBits(midVal);\n                long valueBits  = Double.doubleToLongBits(value);\n\n                if (midValBits < valueBits) {\n                    lo = mid + 1; // (-0.0, 0.0) or (not NaN, NaN); midVal < val\n                } else if (midValBits > valueBits) {\n                    hi = mid - 1; // (0.0, -0.0) or (NaN, not NaN); midVal > val\n                } else {\n                    return mid; // bit patterns are equal; value found\n                }\n            }\n        }\n        return ~lo;  // value not present\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array}.\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     */\n    public static int binarySearch(float[] array, float value) {\n        return binarySearch(array, 0, array.length, value);\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array},\n     * in the range specified by fromIndex (inclusive) and toIndex (exclusive).\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param startIndex the inclusive start index.\n     * @param endIndex the exclusive start index.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     * @throws IllegalArgumentException if {@code startIndex > endIndex}\n     * @throws ArrayIndexOutOfBoundsException if {@code startIndex < 0 || endIndex > array.length}\n     * @since 1.6\n     */\n    public static int binarySearch(float[] array, int startIndex, int endIndex, float value) {\n        checkBinarySearchBounds(startIndex, endIndex, array.length);\n        int lo = startIndex;\n        int hi = endIndex - 1;\n\n        while (lo <= hi) {\n            int mid = (lo + hi) >>> 1;\n            float midVal = array[mid];\n\n            if (midVal < value) {\n                lo = mid + 1;\n            } else if (midVal > value) {\n                hi = mid - 1;\n            } else if (midVal != 0 && midVal == value) {\n                return mid;  // value found\n            } else { // Either midVal and value are == 0 or at least one is NaN\n                int midValBits = Float.floatToIntBits(midVal);\n                int valueBits  = Float.floatToIntBits(value);\n\n                if (midValBits < valueBits) {\n                    lo = mid + 1; // (-0.0, 0.0) or (not NaN, NaN); midVal < val\n                } else if (midValBits > valueBits) {\n                    hi = mid - 1; // (0.0, -0.0) or (NaN, not NaN); midVal > val\n                } else {\n                    return mid; // bit patterns are equal; value found\n                }\n            }\n        }\n        return ~lo;  // value not present\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array}.\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     */\n    public static int binarySearch(int[] array, int value) {\n        return binarySearch(array, 0, array.length, value);\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array},\n     * in the range specified by fromIndex (inclusive) and toIndex (exclusive).\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param startIndex the inclusive start index.\n     * @param endIndex the exclusive start index.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     * @throws IllegalArgumentException if {@code startIndex > endIndex}\n     * @throws ArrayIndexOutOfBoundsException if {@code startIndex < 0 || endIndex > array.length}\n     * @since 1.6\n     */\n    public static int binarySearch(int[] array, int startIndex, int endIndex, int value) {\n        checkBinarySearchBounds(startIndex, endIndex, array.length);\n        int lo = startIndex;\n        int hi = endIndex - 1;\n\n        while (lo <= hi) {\n            int mid = (lo + hi) >>> 1;\n            int midVal = array[mid];\n\n            if (midVal < value) {\n                lo = mid + 1;\n            } else if (midVal > value) {\n                hi = mid - 1;\n            } else {\n                return mid;  // value found\n            }\n        }\n        return ~lo;  // value not present\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array}.\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     */\n    public static int binarySearch(long[] array, long value) {\n        return binarySearch(array, 0, array.length, value);\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array},\n     * in the range specified by fromIndex (inclusive) and toIndex (exclusive).\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param startIndex the inclusive start index.\n     * @param endIndex the exclusive start index.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     * @throws IllegalArgumentException if {@code startIndex > endIndex}\n     * @throws ArrayIndexOutOfBoundsException if {@code startIndex < 0 || endIndex > array.length}\n     * @since 1.6\n     */\n    public static int binarySearch(long[] array, int startIndex, int endIndex, long value) {\n        checkBinarySearchBounds(startIndex, endIndex, array.length);\n        int lo = startIndex;\n        int hi = endIndex - 1;\n\n        while (lo <= hi) {\n            int mid = (lo + hi) >>> 1;\n            long midVal = array[mid];\n\n            if (midVal < value) {\n                lo = mid + 1;\n            } else if (midVal > value) {\n                hi = mid - 1;\n            } else {\n                return mid;  // value found\n            }\n         }\n         return ~lo;  // value not present\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array}.\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     * @throws ClassCastException\n     *         if an element in the array or the search element does not\n     *         implement {@code Comparable}, or cannot be compared to each other.\n     */\n    public static int binarySearch(Object[] array, Object value) {\n        return binarySearch(array, 0, array.length, value);\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array},\n     * in the range specified by fromIndex (inclusive) and toIndex (exclusive).\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param startIndex the inclusive start index.\n     * @param endIndex the exclusive start index.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     * @throws ClassCastException\n     *         if an element in the array or the search element does not\n     *         implement {@code Comparable}, or cannot be compared to each other.\n     * @throws IllegalArgumentException if {@code startIndex > endIndex}\n     * @throws ArrayIndexOutOfBoundsException if {@code startIndex < 0 || endIndex > array.length}\n     * @since 1.6\n     */\n    @SuppressWarnings(\"unchecked\")\n\tpublic static int binarySearch(Object[] array, int startIndex, int endIndex, Object value) {\n        checkBinarySearchBounds(startIndex, endIndex, array.length);\n        int lo = startIndex;\n        int hi = endIndex - 1;\n\n        while (lo <= hi) {\n            int mid = (lo + hi) >>> 1;\n            @SuppressWarnings(\"rawtypes\")\n\t\t\tint midValCmp = ((Comparable) array[mid]).compareTo(value);\n\n            if (midValCmp < 0) {\n                lo = mid + 1;\n            } else if (midValCmp > 0) {\n                hi = mid - 1;\n            } else {\n                return mid;  // value found\n            }\n        }\n        return ~lo;  // value not present\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array},\n     * using {@code comparator} to compare elements.\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param value the element to find.\n     * @param comparator the {@code Comparator} used to compare the elements.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     * @throws ClassCastException\n     *         if an element in the array or the search element does not\n     *         implement {@code Comparable}, or cannot be compared to each other.\n     */\n    public static <T> int binarySearch(T[] array, T value, Comparator<? super T> comparator) {\n        return binarySearch(array, 0, array.length, value, comparator);\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array},\n     * in the range specified by fromIndex (inclusive) and toIndex (exclusive),\n     * using {@code comparator} to compare elements.\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param startIndex the inclusive start index.\n     * @param endIndex the exclusive start index.\n     * @param value the element to find.\n     * @param comparator the {@code Comparator} used to compare the elements.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     * @throws ClassCastException\n     *         if an element in the array or the search element does not\n     *         implement {@code Comparable}, or cannot be compared to each other.\n     * @throws IllegalArgumentException if {@code startIndex > endIndex}\n     * @throws ArrayIndexOutOfBoundsException if {@code startIndex < 0 || endIndex > array.length}\n     * @since 1.6\n     */\n    public static <T> int binarySearch(T[] array, int startIndex, int endIndex, T value,\n            Comparator<? super T> comparator) {\n        if (comparator == null) {\n            return binarySearch(array, startIndex, endIndex, value);\n        }\n\n        checkBinarySearchBounds(startIndex, endIndex, array.length);\n        int lo = startIndex;\n        int hi = endIndex - 1;\n\n        while (lo <= hi) {\n            int mid = (lo + hi) >>> 1;\n            int midValCmp = comparator.compare(array[mid], value);\n\n            if (midValCmp < 0) {\n                lo = mid + 1;\n            } else if (midValCmp > 0) {\n                hi = mid - 1;\n            } else {\n                return mid;  // value found\n            }\n        }\n        return ~lo;  // value not present\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array}.\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     */\n    public static int binarySearch(short[] array, short value) {\n        return binarySearch(array, 0, array.length, value);\n    }\n\n    /**\n     * Performs a binary search for {@code value} in the ascending sorted array {@code array},\n     * in the range specified by fromIndex (inclusive) and toIndex (exclusive).\n     * Searching in an unsorted array has an undefined result. It's also undefined which element\n     * is found if there are multiple occurrences of the same element.\n     *\n     * @param array the sorted array to search.\n     * @param startIndex the inclusive start index.\n     * @param endIndex the exclusive start index.\n     * @param value the element to find.\n     * @return the non-negative index of the element, or a negative index which\n     *         is {@code -index - 1} where the element would be inserted.\n     * @throws IllegalArgumentException if {@code startIndex > endIndex}\n     * @throws ArrayIndexOutOfBoundsException if {@code startIndex < 0 || endIndex > array.length}\n     * @since 1.6\n     */\n    public static int binarySearch(short[] array, int startIndex, int endIndex, short value) {\n        checkBinarySearchBounds(startIndex, endIndex, array.length);\n        int lo = startIndex;\n        int hi = endIndex - 1;\n\n        while (lo <= hi) {\n            int mid = (lo + hi) >>> 1;\n            short midVal = array[mid];\n\n            if (midVal < value) {\n                lo = mid + 1;\n            } else if (midVal > value) {\n                hi = mid - 1;\n            } else {\n                return mid;  // value found\n            }\n        }\n        return ~lo;  // value not present\n    }\n\n    private static void checkBinarySearchBounds(int startIndex, int endIndex, int length) {\n        if (startIndex > endIndex) {\n            throw new IllegalArgumentException();\n        }\n        if (startIndex < 0 || endIndex > length) {\n            throw new ArrayIndexOutOfBoundsException();\n        }\n    }\n\n    /**\n     * Fills the specified array with the specified element.\n     *\n     * @param array\n     *            the {@code byte} array to fill.\n     * @param value\n     *            the {@code byte} element.\n     */\n    public static void fill(byte[] array, byte value) {\n        for (int i = 0; i < array.length; i++) {\n            array[i] = value;\n        }\n    }\n\n   \n\n    /**\n     * Fills the specified array with the specified element.\n     *\n     * @param array\n     *            the {@code int} array to fill.\n     * @param value\n     *            the {@code int} element.\n     */\n    public static void fill(int[] array, int value) {\n        for (int i = 0; i < array.length; i++) {\n            array[i] = value;\n        }\n    }\n\n   \n\n    /**\n     * Fills the specified array with the specified element.\n     *\n     * @param array\n     *            the {@code boolean} array to fill.\n     * @param value\n     *            the {@code boolean} element.\n     */\n    public static void fill(boolean[] array, boolean value) {\n        for (int i = 0; i < array.length; i++) {\n            array[i] = value;\n        }\n    }\n\n   \n\n    /**\n     * Fills the specified array with the specified element.\n     *\n     * @param array\n     *            the {@code Object} array to fill.\n     * @param value\n     *            the {@code Object} element.\n     */\n    public static void fill(Object[] array, Object value) {\n        for (int i = 0; i < array.length; i++) {\n            array[i] = value;\n        }\n    }\n\n  \n\n    /**\n     * Returns a hash code based on the contents of the given array. For any two\n     * {@code boolean} arrays {@code a} and {@code b}, if\n     * {@code Arrays.equals(a, b)} returns {@code true}, it means\n     * that the return value of {@code Arrays.hashCode(a)} equals {@code Arrays.hashCode(b)}.\n     * <p>\n     * The value returned by this method is the same value as the\n     * {@link List#hashCode()} method which is invoked on a {@link List}\n     * containing a sequence of {@link Boolean} instances representing the\n     * elements of array in the same order. If the array is {@code null}, the return\n     * value is 0.\n     *\n     * @param array\n     *            the array whose hash code to compute.\n     * @return the hash code for {@code array}.\n     */\n    public static int hashCode(boolean[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hashCode = 1;\n        for (boolean element : array) {\n            // 1231, 1237 are hash code values for boolean value\n            hashCode = 31 * hashCode + (element ? 1231 : 1237);\n        }\n        return hashCode;\n    }\n\n    /**\n     * Returns a hash code based on the contents of the given array. For any two\n     * not-null {@code int} arrays {@code a} and {@code b}, if\n     * {@code Arrays.equals(a, b)} returns {@code true}, it means\n     * that the return value of {@code Arrays.hashCode(a)} equals {@code Arrays.hashCode(b)}.\n     * <p>\n     * The value returned by this method is the same value as the\n     * {@link List#hashCode()} method which is invoked on a {@link List}\n     * containing a sequence of {@link Integer} instances representing the\n     * elements of array in the same order. If the array is {@code null}, the return\n     * value is 0.\n     *\n     * @param array\n     *            the array whose hash code to compute.\n     * @return the hash code for {@code array}.\n     */\n    public static int hashCode(int[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hashCode = 1;\n        for (int element : array) {\n            // the hash code value for integer value is integer value itself\n            hashCode = 31 * hashCode + element;\n        }\n        return hashCode;\n    }\n\n    /**\n     * Returns a hash code based on the contents of the given array. For any two\n     * {@code short} arrays {@code a} and {@code b}, if\n     * {@code Arrays.equals(a, b)} returns {@code true}, it means\n     * that the return value of {@code Arrays.hashCode(a)} equals {@code Arrays.hashCode(b)}.\n     * <p>\n     * The value returned by this method is the same value as the\n     * {@link List#hashCode()} method which is invoked on a {@link List}\n     * containing a sequence of {@link Short} instances representing the\n     * elements of array in the same order. If the array is {@code null}, the return\n     * value is 0.\n     *\n     * @param array\n     *            the array whose hash code to compute.\n     * @return the hash code for {@code array}.\n     */\n    public static int hashCode(short[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hashCode = 1;\n        for (short element : array) {\n            // the hash code value for short value is its integer value\n            hashCode = 31 * hashCode + element;\n        }\n        return hashCode;\n    }\n\n    /**\n     * Returns a hash code based on the contents of the given array. For any two\n     * {@code char} arrays {@code a} and {@code b}, if\n     * {@code Arrays.equals(a, b)} returns {@code true}, it means\n     * that the return value of {@code Arrays.hashCode(a)} equals {@code Arrays.hashCode(b)}.\n     * <p>\n     * The value returned by this method is the same value as the\n     * {@link List#hashCode()} method which is invoked on a {@link List}\n     * containing a sequence of {@link Character} instances representing the\n     * elements of array in the same order. If the array is {@code null}, the return\n     * value is 0.\n     *\n     * @param array\n     *            the array whose hash code to compute.\n     * @return the hash code for {@code array}.\n     */\n    public static int hashCode(char[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hashCode = 1;\n        for (char element : array) {\n            // the hash code value for char value is its integer value\n            hashCode = 31 * hashCode + element;\n        }\n        return hashCode;\n    }\n\n    /**\n     * Returns a hash code based on the contents of the given array. For any two\n     * {@code byte} arrays {@code a} and {@code b}, if\n     * {@code Arrays.equals(a, b)} returns {@code true}, it means\n     * that the return value of {@code Arrays.hashCode(a)} equals {@code Arrays.hashCode(b)}.\n     * <p>\n     * The value returned by this method is the same value as the\n     * {@link List#hashCode()} method which is invoked on a {@link List}\n     * containing a sequence of {@link Byte} instances representing the\n     * elements of array in the same order. If the array is {@code null}, the return\n     * value is 0.\n     *\n     * @param array\n     *            the array whose hash code to compute.\n     * @return the hash code for {@code array}.\n     */\n    public static int hashCode(byte[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hashCode = 1;\n        for (byte element : array) {\n            // the hash code value for byte value is its integer value\n            hashCode = 31 * hashCode + element;\n        }\n        return hashCode;\n    }\n\n    /**\n     * Returns a hash code based on the contents of the given array. For any two\n     * {@code long} arrays {@code a} and {@code b}, if\n     * {@code Arrays.equals(a, b)} returns {@code true}, it means\n     * that the return value of {@code Arrays.hashCode(a)} equals {@code Arrays.hashCode(b)}.\n     * <p>\n     * The value returned by this method is the same value as the\n     * {@link List#hashCode()} method which is invoked on a {@link List}\n     * containing a sequence of {@link Long} instances representing the\n     * elements of array in the same order. If the array is {@code null}, the return\n     * value is 0.\n     *\n     * @param array\n     *            the array whose hash code to compute.\n     * @return the hash code for {@code array}.\n     */\n    public static int hashCode(long[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hashCode = 1;\n        for (long elementValue : array) {\n            /*\n             * the hash code value for long value is (int) (value ^ (value >>>\n             * 32))\n             */\n            hashCode = 31 * hashCode\n                    + (int) (elementValue ^ (elementValue >>> 32));\n        }\n        return hashCode;\n    }\n\n    /**\n     * Returns a hash code based on the contents of the given array. For any two\n     * {@code float} arrays {@code a} and {@code b}, if\n     * {@code Arrays.equals(a, b)} returns {@code true}, it means\n     * that the return value of {@code Arrays.hashCode(a)} equals {@code Arrays.hashCode(b)}.\n     * <p>\n     * The value returned by this method is the same value as the\n     * {@link List#hashCode()} method which is invoked on a {@link List}\n     * containing a sequence of {@link Float} instances representing the\n     * elements of array in the same order. If the array is {@code null}, the return\n     * value is 0.\n     *\n     * @param array\n     *            the array whose hash code to compute.\n     * @return the hash code for {@code array}.\n     */\n    public static int hashCode(float[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hashCode = 1;\n        for (float element : array) {\n            /*\n             * the hash code value for float value is\n             * Float.floatToIntBits(value)\n             */\n            hashCode = 31 * hashCode + Float.floatToIntBits(element);\n        }\n        return hashCode;\n    }\n\n    /**\n     * Returns a hash code based on the contents of the given array. For any two\n     * {@code double} arrays {@code a} and {@code b}, if\n     * {@code Arrays.equals(a, b)} returns {@code true}, it means\n     * that the return value of {@code Arrays.hashCode(a)} equals {@code Arrays.hashCode(b)}.\n     * <p>\n     * The value returned by this method is the same value as the\n     * {@link List#hashCode()} method which is invoked on a {@link List}\n     * containing a sequence of {@link Double} instances representing the\n     * elements of array in the same order. If the array is {@code null}, the return\n     * value is 0.\n     *\n     * @param array\n     *            the array whose hash code to compute.\n     * @return the hash code for {@code array}.\n     */\n    public static int hashCode(double[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hashCode = 1;\n\n        for (double element : array) {\n            long v = Double.doubleToLongBits(element);\n            /*\n             * the hash code value for double value is (int) (v ^ (v >>> 32))\n             * where v = Double.doubleToLongBits(value)\n             */\n            hashCode = 31 * hashCode + (int) (v ^ (v >>> 32));\n        }\n        return hashCode;\n    }\n\n    /**\n     * Returns a hash code based on the contents of the given array. If the\n     * array contains other arrays as its elements, the hash code is based on\n     * their identities not their contents. So it is acceptable to invoke this\n     * method on an array that contains itself as an element, either directly or\n     * indirectly.\n     * <p>\n     * For any two arrays {@code a} and {@code b}, if\n     * {@code Arrays.equals(a, b)} returns {@code true}, it means\n     * that the return value of {@code Arrays.hashCode(a)} equals\n     * {@code Arrays.hashCode(b)}.\n     * <p>\n     * The value returned by this method is the same value as the method\n     * Arrays.asList(array).hashCode(). If the array is {@code null}, the return value\n     * is 0.\n     *\n     * @param array\n     *            the array whose hash code to compute.\n     * @return the hash code for {@code array}.\n     */\n    public static int hashCode(Object[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hashCode = 1;\n        for (Object element : array) {\n            int elementHashCode;\n\n            if (element == null) {\n                elementHashCode = 0;\n            } else {\n                elementHashCode = (element).hashCode();\n            }\n            hashCode = 31 * hashCode + elementHashCode;\n        }\n        return hashCode;\n    }\n\n    /**\n     * Returns a hash code based on the \"deep contents\" of the given array. If\n     * the array contains other arrays as its elements, the hash code is based\n     * on their contents not their identities. So it is not acceptable to invoke\n     * this method on an array that contains itself as an element, either\n     * directly or indirectly.\n     * <p>\n     * For any two arrays {@code a} and {@code b}, if\n     * {@code Arrays.deepEquals(a, b)} returns {@code true}, it\n     * means that the return value of {@code Arrays.deepHashCode(a)} equals\n     * {@code Arrays.deepHashCode(b)}.\n     * <p>\n     * The computation of the value returned by this method is similar to that\n     * of the value returned by {@link List#hashCode()} invoked on a\n     * {@link List} containing a sequence of instances representing the\n     * elements of array in the same order. The difference is: If an element e\n     * of array is itself an array, its hash code is computed by calling the\n     * appropriate overloading of {@code Arrays.hashCode(e)} if e is an array of a\n     * primitive type, or by calling {@code Arrays.deepHashCode(e)} recursively if e is\n     * an array of a reference type. The value returned by this method is the\n     * same value as the method {@code Arrays.asList(array).hashCode()}. If the array is\n     * {@code null}, the return value is 0.\n     *\n     * @param array\n     *            the array whose hash code to compute.\n     * @return the hash code for {@code array}.\n     */\n    public static int deepHashCode(Object[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hashCode = 1;\n        for (Object element : array) {\n            int elementHashCode = deepHashCodeElement(element);\n            hashCode = 31 * hashCode + elementHashCode;\n        }\n        return hashCode;\n    }\n\n    private static int deepHashCodeElement(Object element) {\n        Class<?> cl;\n        if (element == null) {\n            return 0;\n        }\n\n        cl = element.getClass().getComponentType();\n\n        if (cl == null) {\n            return element.hashCode();\n        }\n\n        /*\n         * element is an array\n         */\n        if (!cl.isPrimitive()) {\n            return deepHashCode((Object[]) element);\n        }\n        if (cl.equals(int.class)) {\n            return hashCode((int[]) element);\n        }\n        if (cl.equals(char.class)) {\n            return hashCode((char[]) element);\n        }\n        if (cl.equals(boolean.class)) {\n            return hashCode((boolean[]) element);\n        }\n        if (cl.equals(byte.class)) {\n            return hashCode((byte[]) element);\n        }\n        if (cl.equals(long.class)) {\n            return hashCode((long[]) element);\n        }\n        if (cl.equals(float.class)) {\n            return hashCode((float[]) element);\n        }\n        if (cl.equals(double.class)) {\n            return hashCode((double[]) element);\n        }\n        return hashCode((short[]) element);\n    }\n\n    /**\n     * Compares the two arrays.\n     *\n     * @param array1\n     *            the first {@code byte} array.\n     * @param array2\n     *            the second {@code byte} array.\n     * @return {@code true} if both arrays are {@code null} or if the arrays have the\n     *         same length and the elements at each index in the two arrays are\n     *         equal, {@code false} otherwise.\n     */\n    public static boolean equals(byte[] array1, byte[] array2) {\n        if (array1 == array2) {\n            return true;\n        }\n        if (array1 == null || array2 == null || array1.length != array2.length) {\n            return false;\n        }\n        for (int i = 0; i < array1.length; i++) {\n            if (array1[i] != array2[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Compares the two arrays.\n     *\n     * @param array1\n     *            the first {@code short} array.\n     * @param array2\n     *            the second {@code short} array.\n     * @return {@code true} if both arrays are {@code null} or if the arrays have the\n     *         same length and the elements at each index in the two arrays are\n     *         equal, {@code false} otherwise.\n     */\n    public static boolean equals(short[] array1, short[] array2) {\n        if (array1 == array2) {\n            return true;\n        }\n        if (array1 == null || array2 == null || array1.length != array2.length) {\n            return false;\n        }\n        for (int i = 0; i < array1.length; i++) {\n            if (array1[i] != array2[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Compares the two arrays.\n     *\n     * @param array1\n     *            the first {@code char} array.\n     * @param array2\n     *            the second {@code char} array.\n     * @return {@code true} if both arrays are {@code null} or if the arrays have the\n     *         same length and the elements at each index in the two arrays are\n     *         equal, {@code false} otherwise.\n     */\n    public static boolean equals(char[] array1, char[] array2) {\n        if (array1 == array2) {\n            return true;\n        }\n        if (array1 == null || array2 == null || array1.length != array2.length) {\n            return false;\n        }\n        for (int i = 0; i < array1.length; i++) {\n            if (array1[i] != array2[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Compares the two arrays.\n     *\n     * @param array1\n     *            the first {@code int} array.\n     * @param array2\n     *            the second {@code int} array.\n     * @return {@code true} if both arrays are {@code null} or if the arrays have the\n     *         same length and the elements at each index in the two arrays are\n     *         equal, {@code false} otherwise.\n     */\n    public static boolean equals(int[] array1, int[] array2) {\n        if (array1 == array2) {\n            return true;\n        }\n        if (array1 == null || array2 == null || array1.length != array2.length) {\n            return false;\n        }\n        for (int i = 0; i < array1.length; i++) {\n            if (array1[i] != array2[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Compares the two arrays.\n     *\n     * @param array1\n     *            the first {@code long} array.\n     * @param array2\n     *            the second {@code long} array.\n     * @return {@code true} if both arrays are {@code null} or if the arrays have the\n     *         same length and the elements at each index in the two arrays are\n     *         equal, {@code false} otherwise.\n     */\n    public static boolean equals(long[] array1, long[] array2) {\n        if (array1 == array2) {\n            return true;\n        }\n        if (array1 == null || array2 == null || array1.length != array2.length) {\n            return false;\n        }\n        for (int i = 0; i < array1.length; i++) {\n            if (array1[i] != array2[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Compares the two arrays. The values are compared in the same manner as\n     * {@code Float.equals()}.\n     *\n     * @param array1\n     *            the first {@code float} array.\n     * @param array2\n     *            the second {@code float} array.\n     * @return {@code true} if both arrays are {@code null} or if the arrays have the\n     *         same length and the elements at each index in the two arrays are\n     *         equal, {@code false} otherwise.\n     * @see Float#equals(Object)\n     */\n    public static boolean equals(float[] array1, float[] array2) {\n        if (array1 == array2) {\n            return true;\n        }\n        if (array1 == null || array2 == null || array1.length != array2.length) {\n            return false;\n        }\n        for (int i = 0; i < array1.length; i++) {\n            if (Float.floatToIntBits(array1[i]) != Float\n                    .floatToIntBits(array2[i])) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Compares the two arrays. The values are compared in the same manner as\n     * {@code Double.equals()}.\n     *\n     * @param array1\n     *            the first {@code double} array.\n     * @param array2\n     *            the second {@code double} array.\n     * @return {@code true} if both arrays are {@code null} or if the arrays have the\n     *         same length and the elements at each index in the two arrays are\n     *         equal, {@code false} otherwise.\n     * @see Double#equals(Object)\n     */\n    public static boolean equals(double[] array1, double[] array2) {\n        if (array1 == array2) {\n            return true;\n        }\n        if (array1 == null || array2 == null || array1.length != array2.length) {\n            return false;\n        }\n        for (int i = 0; i < array1.length; i++) {\n            if (Double.doubleToLongBits(array1[i]) != Double\n                    .doubleToLongBits(array2[i])) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Compares the two arrays.\n     *\n     * @param array1\n     *            the first {@code boolean} array.\n     * @param array2\n     *            the second {@code boolean} array.\n     * @return {@code true} if both arrays are {@code null} or if the arrays have the\n     *         same length and the elements at each index in the two arrays are\n     *         equal, {@code false} otherwise.\n     */\n    public static boolean equals(boolean[] array1, boolean[] array2) {\n        if (array1 == array2) {\n            return true;\n        }\n        if (array1 == null || array2 == null || array1.length != array2.length) {\n            return false;\n        }\n        for (int i = 0; i < array1.length; i++) {\n            if (array1[i] != array2[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Compares the two arrays.\n     *\n     * @param array1\n     *            the first {@code Object} array.\n     * @param array2\n     *            the second {@code Object} array.\n     * @return {@code true} if both arrays are {@code null} or if the arrays have the\n     *         same length and the elements at each index in the two arrays are\n     *         equal according to {@code equals()}, {@code false} otherwise.\n     */\n    public static boolean equals(Object[] array1, Object[] array2) {\n        if (array1 == array2) {\n            return true;\n        }\n        if (array1 == null || array2 == null || array1.length != array2.length) {\n            return false;\n        }\n        for (int i = 0; i < array1.length; i++) {\n            Object e1 = array1[i], e2 = array2[i];\n            if (!(e1 == null ? e2 == null : e1.equals(e2))) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Returns {@code true} if the two given arrays are deeply equal to one another.\n     * Unlike the method {@code equals(Object[] array1, Object[] array2)}, this method\n     * is appropriate for use for nested arrays of arbitrary depth.\n     * <p>\n     * Two array references are considered deeply equal if they are both {@code null},\n     * or if they refer to arrays that have the same length and the elements at\n     * each index in the two arrays are equal.\n     * <p>\n     * Two {@code null} elements {@code element1} and {@code element2} are possibly deeply equal if any\n     * of the following conditions satisfied:\n     * <p>\n     * {@code element1} and {@code element2} are both arrays of object reference types, and\n     * {@code Arrays.deepEquals(element1, element2)} would return {@code true}.\n     * <p>\n     * {@code element1} and {@code element2} are arrays of the same primitive type, and the\n     * appropriate overloading of {@code Arrays.equals(element1, element2)} would return\n     * {@code true}.\n     * <p>\n     * {@code element1 == element2}\n     * <p>\n     * {@code element1.equals(element2)} would return {@code true}.\n     * <p>\n     * Note that this definition permits {@code null} elements at any depth.\n     * <p>\n     * If either of the given arrays contain themselves as elements, the\n     * behavior of this method is uncertain.\n     *\n     * @param array1\n     *            the first {@code Object} array.\n     * @param array2\n     *            the second {@code Object} array.\n     * @return {@code true} if both arrays are {@code null} or if the arrays have the\n     *         same length and the elements at each index in the two arrays are\n     *         equal according to {@code equals()}, {@code false} otherwise.\n     */\n    public static boolean deepEquals(Object[] array1, Object[] array2) {\n        if (array1 == array2) {\n            return true;\n        }\n        if (array1 == null || array2 == null || array1.length != array2.length) {\n            return false;\n        }\n        for (int i = 0; i < array1.length; i++) {\n            Object e1 = array1[i], e2 = array2[i];\n\n            if (!deepEqualsElements(e1, e2)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private static boolean deepEqualsElements(Object e1, Object e2) {\n        Class<?> cl1, cl2;\n\n        if (e1 == e2) {\n            return true;\n        }\n\n        if (e1 == null || e2 == null) {\n            return false;\n        }\n\n        cl1 = e1.getClass().getComponentType();\n        cl2 = e2.getClass().getComponentType();\n\n        if (cl1 != cl2) {\n            return false;\n        }\n\n        if (cl1 == null) {\n            return e1.equals(e2);\n        }\n\n        /*\n         * compare as arrays\n         */\n        if (!cl1.isPrimitive()) {\n            return deepEquals((Object[]) e1, (Object[]) e2);\n        }\n\n        if (cl1.equals(int.class)) {\n            return equals((int[]) e1, (int[]) e2);\n        }\n        if (cl1.equals(char.class)) {\n            return equals((char[]) e1, (char[]) e2);\n        }\n        if (cl1.equals(boolean.class)) {\n            return equals((boolean[]) e1, (boolean[]) e2);\n        }\n        if (cl1.equals(byte.class)) {\n            return equals((byte[]) e1, (byte[]) e2);\n        }\n        if (cl1.equals(long.class)) {\n            return equals((long[]) e1, (long[]) e2);\n        }\n        if (cl1.equals(float.class)) {\n            return equals((float[]) e1, (float[]) e2);\n        }\n        if (cl1.equals(double.class)) {\n            return equals((double[]) e1, (double[]) e2);\n        }\n        return equals((short[]) e1, (short[]) e2);\n    }\n\n   \n\n    /**\n     * Sorts the specified range in the array in ascending numerical order.\n     *\n     * @param array\n     *            the {@code byte} array to be sorted.\n     * @param start\n     *            the start index to sort.\n     * @param end\n     *            the last + 1 index to sort.\n     * @throws IllegalArgumentException\n     *                if {@code start > end}.\n     * @throws ArrayIndexOutOfBoundsException\n     *                if {@code start < 0} or {@code end > array.length}.\n     */\n  \n\n    /**\n     * Creates a {@code String} representation of the {@code boolean[]} passed.\n     * The result is surrounded by brackets ({@code \"[]\"}), each\n     * element is converted to a {@code String} via the\n     * {@link String#valueOf(boolean)} and separated by {@code \", \"}.\n     * If the array is {@code null}, then {@code \"null\"} is returned.\n     *\n     * @param array\n     *            the {@code boolean} array to convert.\n     * @return the {@code String} representation of {@code array}.\n     * @since 1.5\n     */\n    public static String toString(boolean[] array) {\n        if (array == null) {\n            return \"null\";\n        }\n        if (array.length == 0) {\n            return \"[]\";\n        }\n        StringBuilder sb = new StringBuilder(array.length * 7);\n        sb.append('[');\n        sb.append(array[0]);\n        for (int i = 1; i < array.length; i++) {\n            sb.append(\", \");\n            sb.append(array[i]);\n        }\n        sb.append(']');\n        return sb.toString();\n    }\n\n    /**\n     * Creates a {@code String} representation of the {@code byte[]} passed. The\n     * result is surrounded by brackets ({@code \"[]\"}), each element\n     * is converted to a {@code String} via the {@link String#valueOf(int)} and\n     * separated by {@code \", \"}. If the array is {@code null}, then\n     * {@code \"null\"} is returned.\n     *\n     * @param array\n     *            the {@code byte} array to convert.\n     * @return the {@code String} representation of {@code array}.\n     * @since 1.5\n     */\n    public static String toString(byte[] array) {\n        if (array == null) {\n            return \"null\";\n        }\n        if (array.length == 0) {\n            return \"[]\";\n        }\n        StringBuilder sb = new StringBuilder(array.length * 6);\n        sb.append('[');\n        sb.append(array[0]);\n        for (int i = 1; i < array.length; i++) {\n            sb.append(\", \");\n            sb.append(array[i]);\n        }\n        sb.append(']');\n        return sb.toString();\n    }\n\n    /**\n     * Creates a {@code String} representation of the {@code char[]} passed. The\n     * result is surrounded by brackets ({@code \"[]\"}), each element\n     * is converted to a {@code String} via the {@link String#valueOf(char)} and\n     * separated by {@code \", \"}. If the array is {@code null}, then\n     * {@code \"null\"} is returned.\n     *\n     * @param array\n     *            the {@code char} array to convert.\n     * @return the {@code String} representation of {@code array}.\n     * @since 1.5\n     */\n    public static String toString(char[] array) {\n        if (array == null) {\n            return \"null\";\n        }\n        if (array.length == 0) {\n            return \"[]\";\n        }\n        StringBuilder sb = new StringBuilder(array.length * 3);\n        sb.append('[');\n        sb.append(array[0]);\n        for (int i = 1; i < array.length; i++) {\n            sb.append(\", \");\n            sb.append(array[i]);\n        }\n        sb.append(']');\n        return sb.toString();\n    }\n\n    /**\n     * Creates a {@code String} representation of the {@code double[]} passed.\n     * The result is surrounded by brackets ({@code \"[]\"}), each\n     * element is converted to a {@code String} via the\n     * {@link String#valueOf(double)} and separated by {@code \", \"}.\n     * If the array is {@code null}, then {@code \"null\"} is returned.\n     *\n     * @param array\n     *            the {@code double} array to convert.\n     * @return the {@code String} representation of {@code array}.\n     * @since 1.5\n     */\n    public static String toString(double[] array) {\n        if (array == null) {\n            return \"null\";\n        }\n        if (array.length == 0) {\n            return \"[]\";\n        }\n        StringBuilder sb = new StringBuilder(array.length * 7);\n        sb.append('[');\n        sb.append(array[0]);\n        for (int i = 1; i < array.length; i++) {\n            sb.append(\", \");\n            sb.append(array[i]);\n        }\n        sb.append(']');\n        return sb.toString();\n    }\n\n    /**\n     * Creates a {@code String} representation of the {@code float[]} passed.\n     * The result is surrounded by brackets ({@code \"[]\"}), each\n     * element is converted to a {@code String} via the\n     * {@link String#valueOf(float)} and separated by {@code \", \"}.\n     * If the array is {@code null}, then {@code \"null\"} is returned.\n     *\n     * @param array\n     *            the {@code float} array to convert.\n     * @return the {@code String} representation of {@code array}.\n     * @since 1.5\n     */\n    public static String toString(float[] array) {\n        if (array == null) {\n            return \"null\";\n        }\n        if (array.length == 0) {\n            return \"[]\";\n        }\n        StringBuilder sb = new StringBuilder(array.length * 7);\n        sb.append('[');\n        sb.append(array[0]);\n        for (int i = 1; i < array.length; i++) {\n            sb.append(\", \");\n            sb.append(array[i]);\n        }\n        sb.append(']');\n        return sb.toString();\n    }\n\n    /**\n     * Creates a {@code String} representation of the {@code int[]} passed. The\n     * result is surrounded by brackets ({@code \"[]\"}), each element\n     * is converted to a {@code String} via the {@link String#valueOf(int)} and\n     * separated by {@code \", \"}. If the array is {@code null}, then\n     * {@code \"null\"} is returned.\n     *\n     * @param array\n     *            the {@code int} array to convert.\n     * @return the {@code String} representation of {@code array}.\n     * @since 1.5\n     */\n    public static String toString(int[] array) {\n        if (array == null) {\n            return \"null\";\n        }\n        if (array.length == 0) {\n            return \"[]\";\n        }\n        StringBuilder sb = new StringBuilder(array.length * 6);\n        sb.append('[');\n        sb.append(array[0]);\n        for (int i = 1; i < array.length; i++) {\n            sb.append(\", \");\n            sb.append(array[i]);\n        }\n        sb.append(']');\n        return sb.toString();\n    }\n\n    /**\n     * Creates a {@code String} representation of the {@code long[]} passed. The\n     * result is surrounded by brackets ({@code \"[]\"}), each element\n     * is converted to a {@code String} via the {@link String#valueOf(long)} and\n     * separated by {@code \", \"}. If the array is {@code null}, then\n     * {@code \"null\"} is returned.\n     *\n     * @param array\n     *            the {@code long} array to convert.\n     * @return the {@code String} representation of {@code array}.\n     * @since 1.5\n     */\n    public static String toString(long[] array) {\n        if (array == null) {\n            return \"null\";\n        }\n        if (array.length == 0) {\n            return \"[]\";\n        }\n        StringBuilder sb = new StringBuilder(array.length * 6);\n        sb.append('[');\n        sb.append(array[0]);\n        for (int i = 1; i < array.length; i++) {\n            sb.append(\", \");\n            sb.append(array[i]);\n        }\n        sb.append(']');\n        return sb.toString();\n    }\n\n    /**\n     * Creates a {@code String} representation of the {@code short[]} passed.\n     * The result is surrounded by brackets ({@code \"[]\"}), each\n     * element is converted to a {@code String} via the\n     * {@link String#valueOf(int)} and separated by {@code \", \"}. If\n     * the array is {@code null}, then {@code \"null\"} is returned.\n     *\n     * @param array\n     *            the {@code short} array to convert.\n     * @return the {@code String} representation of {@code array}.\n     * @since 1.5\n     */\n    public static String toString(short[] array) {\n        if (array == null) {\n            return \"null\";\n        }\n        if (array.length == 0) {\n            return \"[]\";\n        }\n        StringBuilder sb = new StringBuilder(array.length * 6);\n        sb.append('[');\n        sb.append(array[0]);\n        for (int i = 1; i < array.length; i++) {\n            sb.append(\", \");\n            sb.append(array[i]);\n        }\n        sb.append(']');\n        return sb.toString();\n    }\n\n    /**\n     * Creates a {@code String} representation of the {@code Object[]} passed.\n     * The result is surrounded by brackets ({@code \"[]\"}), each\n     * element is converted to a {@code String} via the\n     * {@link String#valueOf(Object)} and separated by {@code \", \"}.\n     * If the array is {@code null}, then {@code \"null\"} is returned.\n     *\n     * @param array\n     *            the {@code Object} array to convert.\n     * @return the {@code String} representation of {@code array}.\n     * @since 1.5\n     */\n    public static String toString(Object[] array) {\n        if (array == null) {\n            return \"null\";\n        }\n        if (array.length == 0) {\n            return \"[]\";\n        }\n        StringBuilder sb = new StringBuilder(array.length * 7);\n        sb.append('[');\n        sb.append(array[0]);\n        for (int i = 1; i < array.length; i++) {\n            sb.append(\", \");\n            sb.append(array[i]);\n        }\n        sb.append(']');\n        return sb.toString();\n    }\n\n    /**\n     * Creates a <i>\"deep\"</i> {@code String} representation of the\n     * {@code Object[]} passed, such that if the array contains other arrays,\n     * the {@code String} representation of those arrays is generated as well.\n     * <p>\n     * If any of the elements are primitive arrays, the generation is delegated\n     * to the other {@code toString} methods in this class. If any element\n     * contains a reference to the original array, then it will be represented\n     * as {@code \"[...]\"}. If an element is an {@code Object[]}, then its\n     * representation is generated by a recursive call to this method. All other\n     * elements are converted via the {@link String#valueOf(Object)} method.\n     *\n     * @param array\n     *            the {@code Object} array to convert.\n     * @return the {@code String} representation of {@code array}.\n     * @since 1.5\n     */\n    public static String deepToString(Object[] array) {\n        // Special case null to prevent NPE\n        if (array == null) {\n            return \"null\";\n        }\n        // delegate this to the recursive method\n        StringBuilder buf = new StringBuilder(array.length * 9);\n        deepToStringImpl(array, new Object[] { array }, buf);\n        return buf.toString();\n    }\n\n    /**\n     * Implementation method used by {@link #deepToString(Object[])}.\n     *\n     * @param array\n     *            the {@code Object[]} to dive into.\n     * @param origArrays\n     *            the original {@code Object[]}; used to test for self\n     *            references.\n     * @param sb\n     *            the {@code StringBuilder} instance to append to or\n     *            {@code null} one hasn't been created yet.\n     * @return the result.\n     * @see #deepToString(Object[])\n     */\n    private static void deepToStringImpl(Object[] array, Object[] origArrays,\n            StringBuilder sb) {\n        if (array == null) {\n            sb.append(\"null\");\n            return;\n        }\n\n        sb.append('[');\n\n        for (int i = 0; i < array.length; i++) {\n            if (i != 0) {\n                sb.append(\", \");\n            }\n            // establish current element\n            Object elem = array[i];\n            if (elem == null) {\n                // element is null\n                sb.append(\"null\");\n            } else {\n                // get the Class of the current element\n                Class<?> elemClass = elem.getClass();\n                if (elemClass.isArray()) {\n                    // element is an array type\n\n                    // get the declared Class of the array (element)\n                    Class<?> elemElemClass = elemClass.getComponentType();\n                    if (elemElemClass.isPrimitive()) {\n                        // element is a primitive array\n                        if (boolean.class.equals(elemElemClass)) {\n                            sb.append(toString((boolean[]) elem));\n                        } else if (byte.class.equals(elemElemClass)) {\n                            sb.append(toString((byte[]) elem));\n                        } else if (char.class.equals(elemElemClass)) {\n                            sb.append(toString((char[]) elem));\n                        } else if (double.class.equals(elemElemClass)) {\n                            sb.append(toString((double[]) elem));\n                        } else if (float.class.equals(elemElemClass)) {\n                            sb.append(toString((float[]) elem));\n                        } else if (int.class.equals(elemElemClass)) {\n                            sb.append(toString((int[]) elem));\n                        } else if (long.class.equals(elemElemClass)) {\n                            sb.append(toString((long[]) elem));\n                        } else if (short.class.equals(elemElemClass)) {\n                            sb.append(toString((short[]) elem));\n                        } else {\n                            // no other possible primitives, so we assert that\n                            throw new AssertionError();\n                        }\n                    } else {\n                        // element is an Object[], so we assert that\n                        assert elem instanceof Object[];\n                        if (deepToStringImplContains(origArrays, elem)) {\n                            sb.append(\"[...]\");\n                        } else {\n                            Object[] newArray = (Object[]) elem;\n                            Object[] newOrigArrays = new Object[origArrays.length + 1];\n                            System.arraycopy(origArrays, 0, newOrigArrays, 0,\n                                    origArrays.length);\n                            newOrigArrays[origArrays.length] = newArray;\n                            // make the recursive call to this method\n                            deepToStringImpl(newArray, newOrigArrays, sb);\n                        }\n                    }\n                } else { // element is NOT an array, just an Object\n                    sb.append(array[i]);\n                }\n            }\n        }\n        sb.append(']');\n    }\n\n    /**\n     * Utility method used to assist the implementation of\n     * {@link #deepToString(Object[])}.\n     *\n     * @param origArrays\n     *            An array of Object[] references.\n     * @param array\n     *            An Object[] reference to look for in {@code origArrays}.\n     * @return A value of {@code true} if {@code array} is an\n     *         element in {@code origArrays}.\n     */\n    private static boolean deepToStringImplContains(Object[] origArrays,\n            Object array) {\n        if (origArrays == null || origArrays.length == 0) {\n            return false;\n        }\n        for (Object element : origArrays) {\n            if (element == array) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Copies {@code newLength} elements from {@code original} into a new array.\n     * If {@code newLength} is greater than {@code original.length}, the result is padded\n     * with the value {@code false}.\n     *\n     * @param original the original array\n     * @param newLength the length of the new array\n     * @return the new array\n     * @throws NegativeArraySizeException if {@code newLength < 0}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static boolean[] copyOf(boolean[] original, int newLength) {\n        if (newLength < 0) {\n            throw new NegativeArraySizeException();\n        }\n        return copyOfRange(original, 0, newLength);\n    }\n\n    /**\n     * Copies {@code newLength} elements from {@code original} into a new array.\n     * If {@code newLength} is greater than {@code original.length}, the result is padded\n     * with the value {@code (byte) 0}.\n     *\n     * @param original the original array\n     * @param newLength the length of the new array\n     * @return the new array\n     * @throws NegativeArraySizeException if {@code newLength < 0}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static byte[] copyOf(byte[] original, int newLength) {\n        if (newLength < 0) {\n            throw new NegativeArraySizeException();\n        }\n        return copyOfRange(original, 0, newLength);\n    }\n\n    /**\n     * Copies {@code newLength} elements from {@code original} into a new array.\n     * If {@code newLength} is greater than {@code original.length}, the result is padded\n     * with the value {@code '\\\\u0000'}.\n     *\n     * @param original the original array\n     * @param newLength the length of the new array\n     * @return the new array\n     * @throws NegativeArraySizeException if {@code newLength < 0}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static char[] copyOf(char[] original, int newLength) {\n        if (newLength < 0) {\n            throw new NegativeArraySizeException();\n        }\n        return copyOfRange(original, 0, newLength);\n    }\n\n    /**\n     * Copies {@code newLength} elements from {@code original} into a new array.\n     * If {@code newLength} is greater than {@code original.length}, the result is padded\n     * with the value {@code 0.0d}.\n     *\n     * @param original the original array\n     * @param newLength the length of the new array\n     * @return the new array\n     * @throws NegativeArraySizeException if {@code newLength < 0}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static double[] copyOf(double[] original, int newLength) {\n        if (newLength < 0) {\n            throw new NegativeArraySizeException();\n        }\n        return copyOfRange(original, 0, newLength);\n    }\n\n    /**\n     * Copies {@code newLength} elements from {@code original} into a new array.\n     * If {@code newLength} is greater than {@code original.length}, the result is padded\n     * with the value {@code 0.0f}.\n     *\n     * @param original the original array\n     * @param newLength the length of the new array\n     * @return the new array\n     * @throws NegativeArraySizeException if {@code newLength < 0}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static float[] copyOf(float[] original, int newLength) {\n        if (newLength < 0) {\n            throw new NegativeArraySizeException();\n        }\n        return copyOfRange(original, 0, newLength);\n    }\n\n    /**\n     * Copies {@code newLength} elements from {@code original} into a new array.\n     * If {@code newLength} is greater than {@code original.length}, the result is padded\n     * with the value {@code 0}.\n     *\n     * @param original the original array\n     * @param newLength the length of the new array\n     * @return the new array\n     * @throws NegativeArraySizeException if {@code newLength < 0}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static int[] copyOf(int[] original, int newLength) {\n        if (newLength < 0) {\n            throw new NegativeArraySizeException();\n        }\n        return copyOfRange(original, 0, newLength);\n    }\n\n    /**\n     * Copies {@code newLength} elements from {@code original} into a new array.\n     * If {@code newLength} is greater than {@code original.length}, the result is padded\n     * with the value {@code 0L}.\n     *\n     * @param original the original array\n     * @param newLength the length of the new array\n     * @return the new array\n     * @throws NegativeArraySizeException if {@code newLength < 0}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static long[] copyOf(long[] original, int newLength) {\n        if (newLength < 0) {\n            throw new NegativeArraySizeException();\n        }\n        return copyOfRange(original, 0, newLength);\n    }\n\n    /**\n     * Copies {@code newLength} elements from {@code original} into a new array.\n     * If {@code newLength} is greater than {@code original.length}, the result is padded\n     * with the value {@code (short) 0}.\n     *\n     * @param original the original array\n     * @param newLength the length of the new array\n     * @return the new array\n     * @throws NegativeArraySizeException if {@code newLength < 0}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static short[] copyOf(short[] original, int newLength) {\n        if (newLength < 0) {\n            throw new NegativeArraySizeException();\n        }\n        return copyOfRange(original, 0, newLength);\n    }\n\n    /**\n     * Copies {@code newLength} elements from {@code original} into a new array.\n     * If {@code newLength} is greater than {@code original.length}, the result is padded\n     * with the value {@code null}.\n     *\n     * @param original the original array\n     * @param newLength the length of the new array\n     * @return the new array\n     * @throws NegativeArraySizeException if {@code newLength < 0}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static <T> T[] copyOf(T[] original, int newLength) {\n        if (original == null) {\n            throw new NullPointerException();\n        }\n        if (newLength < 0) {\n            throw new NegativeArraySizeException();\n        }\n        return copyOfRange(original, 0, newLength);\n    }\n\n    /**\n     * Copies {@code newLength} elements from {@code original} into a new array.\n     * If {@code newLength} is greater than {@code original.length}, the result is padded\n     * with the value {@code null}.\n     *\n     * @param original the original array\n     * @param newLength the length of the new array\n     * @param newType the class of the new array\n     * @return the new array\n     * @throws NegativeArraySizeException if {@code newLength < 0}\n     * @throws NullPointerException if {@code original == null}\n     * @throws ArrayStoreException if a value in {@code original} is incompatible with T\n     * @since 1.6\n     */\n    public static <T, U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {\n        // We use the null pointer check in copyOfRange for exception priority compatibility.\n        if (newLength < 0) {\n            throw new NegativeArraySizeException();\n        }\n        return copyOfRange(original, 0, newLength, newType);\n    }\n\n    /**\n     * Copies elements from {@code original} into a new array, from indexes start (inclusive) to\n     * end (exclusive). The original order of elements is preserved.\n     * If {@code end} is greater than {@code original.length}, the result is padded\n     * with the value {@code false}.\n     *\n     * @param original the original array\n     * @param start the start index, inclusive\n     * @param end the end index, exclusive\n     * @return the new array\n     * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length}\n     * @throws IllegalArgumentException if {@code start > end}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static boolean[] copyOfRange(boolean[] original, int start, int end) {\n        if (start > end) {\n            throw new IllegalArgumentException();\n        }\n        int originalLength = original.length;\n        if (start < 0 || start > originalLength) {\n            throw new ArrayIndexOutOfBoundsException();\n        }\n        int resultLength = end - start;\n        int copyLength = Math.min(resultLength, originalLength - start);\n        boolean[] result = new boolean[resultLength];\n        System.arraycopy(original, start, result, 0, copyLength);\n        return result;\n    }\n\n    /**\n     * Copies elements from {@code original} into a new array, from indexes start (inclusive) to\n     * end (exclusive). The original order of elements is preserved.\n     * If {@code end} is greater than {@code original.length}, the result is padded\n     * with the value {@code (byte) 0}.\n     *\n     * @param original the original array\n     * @param start the start index, inclusive\n     * @param end the end index, exclusive\n     * @return the new array\n     * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length}\n     * @throws IllegalArgumentException if {@code start > end}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static byte[] copyOfRange(byte[] original, int start, int end) {\n        if (start > end) {\n            throw new IllegalArgumentException();\n        }\n        int originalLength = original.length;\n        if (start < 0 || start > originalLength) {\n            throw new ArrayIndexOutOfBoundsException();\n        }\n        int resultLength = end - start;\n        int copyLength = Math.min(resultLength, originalLength - start);\n        byte[] result = new byte[resultLength];\n        System.arraycopy(original, start, result, 0, copyLength);\n        return result;\n    }\n\n    /**\n     * Copies elements from {@code original} into a new array, from indexes start (inclusive) to\n     * end (exclusive). The original order of elements is preserved.\n     * If {@code end} is greater than {@code original.length}, the result is padded\n     * with the value {@code '\\\\u0000'}.\n     *\n     * @param original the original array\n     * @param start the start index, inclusive\n     * @param end the end index, exclusive\n     * @return the new array\n     * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length}\n     * @throws IllegalArgumentException if {@code start > end}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static char[] copyOfRange(char[] original, int start, int end) {\n        if (start > end) {\n            throw new IllegalArgumentException();\n        }\n        int originalLength = original.length;\n        if (start < 0 || start > originalLength) {\n            throw new ArrayIndexOutOfBoundsException();\n        }\n        int resultLength = end - start;\n        int copyLength = Math.min(resultLength, originalLength - start);\n        char[] result = new char[resultLength];\n        System.arraycopy(original, start, result, 0, copyLength);\n        return result;\n    }\n\n    /**\n     * Copies elements from {@code original} into a new array, from indexes start (inclusive) to\n     * end (exclusive). The original order of elements is preserved.\n     * If {@code end} is greater than {@code original.length}, the result is padded\n     * with the value {@code 0.0d}.\n     *\n     * @param original the original array\n     * @param start the start index, inclusive\n     * @param end the end index, exclusive\n     * @return the new array\n     * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length}\n     * @throws IllegalArgumentException if {@code start > end}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static double[] copyOfRange(double[] original, int start, int end) {\n        if (start > end) {\n            throw new IllegalArgumentException();\n        }\n        int originalLength = original.length;\n        if (start < 0 || start > originalLength) {\n            throw new ArrayIndexOutOfBoundsException();\n        }\n        int resultLength = end - start;\n        int copyLength = Math.min(resultLength, originalLength - start);\n        double[] result = new double[resultLength];\n        System.arraycopy(original, start, result, 0, copyLength);\n        return result;\n    }\n\n    /**\n     * Copies elements from {@code original} into a new array, from indexes start (inclusive) to\n     * end (exclusive). The original order of elements is preserved.\n     * If {@code end} is greater than {@code original.length}, the result is padded\n     * with the value {@code 0.0f}.\n     *\n     * @param original the original array\n     * @param start the start index, inclusive\n     * @param end the end index, exclusive\n     * @return the new array\n     * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length}\n     * @throws IllegalArgumentException if {@code start > end}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static float[] copyOfRange(float[] original, int start, int end) {\n        if (start > end) {\n            throw new IllegalArgumentException();\n        }\n        int originalLength = original.length;\n        if (start < 0 || start > originalLength) {\n            throw new ArrayIndexOutOfBoundsException();\n        }\n        int resultLength = end - start;\n        int copyLength = Math.min(resultLength, originalLength - start);\n        float[] result = new float[resultLength];\n        System.arraycopy(original, start, result, 0, copyLength);\n        return result;\n    }\n\n    /**\n     * Copies elements from {@code original} into a new array, from indexes start (inclusive) to\n     * end (exclusive). The original order of elements is preserved.\n     * If {@code end} is greater than {@code original.length}, the result is padded\n     * with the value {@code 0}.\n     *\n     * @param original the original array\n     * @param start the start index, inclusive\n     * @param end the end index, exclusive\n     * @return the new array\n     * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length}\n     * @throws IllegalArgumentException if {@code start > end}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static int[] copyOfRange(int[] original, int start, int end) {\n        if (start > end) {\n            throw new IllegalArgumentException();\n        }\n        int originalLength = original.length;\n        if (start < 0 || start > originalLength) {\n            throw new ArrayIndexOutOfBoundsException();\n        }\n        int resultLength = end - start;\n        int copyLength = Math.min(resultLength, originalLength - start);\n        int[] result = new int[resultLength];\n        System.arraycopy(original, start, result, 0, copyLength);\n        return result;\n    }\n\n    /**\n     * Copies elements from {@code original} into a new array, from indexes start (inclusive) to\n     * end (exclusive). The original order of elements is preserved.\n     * If {@code end} is greater than {@code original.length}, the result is padded\n     * with the value {@code 0L}.\n     *\n     * @param original the original array\n     * @param start the start index, inclusive\n     * @param end the end index, exclusive\n     * @return the new array\n     * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length}\n     * @throws IllegalArgumentException if {@code start > end}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static long[] copyOfRange(long[] original, int start, int end) {\n        if (start > end) {\n            throw new IllegalArgumentException();\n        }\n        int originalLength = original.length;\n        if (start < 0 || start > originalLength) {\n            throw new ArrayIndexOutOfBoundsException();\n        }\n        int resultLength = end - start;\n        int copyLength = Math.min(resultLength, originalLength - start);\n        long[] result = new long[resultLength];\n        System.arraycopy(original, start, result, 0, copyLength);\n        return result;\n    }\n\n    /**\n     * Copies elements from {@code original} into a new array, from indexes start (inclusive) to\n     * end (exclusive). The original order of elements is preserved.\n     * If {@code end} is greater than {@code original.length}, the result is padded\n     * with the value {@code (short) 0}.\n     *\n     * @param original the original array\n     * @param start the start index, inclusive\n     * @param end the end index, exclusive\n     * @return the new array\n     * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length}\n     * @throws IllegalArgumentException if {@code start > end}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    public static short[] copyOfRange(short[] original, int start, int end) {\n        if (start > end) {\n            throw new IllegalArgumentException();\n        }\n        int originalLength = original.length;\n        if (start < 0 || start > originalLength) {\n            throw new ArrayIndexOutOfBoundsException();\n        }\n        int resultLength = end - start;\n        int copyLength = Math.min(resultLength, originalLength - start);\n        short[] result = new short[resultLength];\n        System.arraycopy(original, start, result, 0, copyLength);\n        return result;\n    }\n\n    /**\n     * Copies elements from {@code original} into a new array, from indexes start (inclusive) to\n     * end (exclusive). The original order of elements is preserved.\n     * If {@code end} is greater than {@code original.length}, the result is padded\n     * with the value {@code null}.\n     *\n     * @param original the original array\n     * @param start the start index, inclusive\n     * @param end the end index, exclusive\n     * @return the new array\n     * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length}\n     * @throws IllegalArgumentException if {@code start > end}\n     * @throws NullPointerException if {@code original == null}\n     * @since 1.6\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T[] copyOfRange(T[] original, int start, int end) {\n        int originalLength = original.length; // For exception priority compatibility.\n        if (start > end) {\n            throw new IllegalArgumentException();\n        }\n        if (start < 0 || start > originalLength) {\n            throw new ArrayIndexOutOfBoundsException();\n        }\n        int resultLength = end - start;\n        int copyLength = Math.min(resultLength, originalLength - start);\n        T[] result = (T[]) Array.newInstance(original.getClass().getComponentType(), resultLength);\n        System.arraycopy(original, start, result, 0, copyLength);\n        return result;\n    }\n\n    /**\n     * Copies elements from {@code original} into a new array, from indexes start (inclusive) to\n     * end (exclusive). The original order of elements is preserved.\n     * If {@code end} is greater than {@code original.length}, the result is padded\n     * with the value {@code null}.\n     *\n     * @param original the original array\n     * @param start the start index, inclusive\n     * @param end the end index, exclusive\n     * @return the new array\n     * @throws ArrayIndexOutOfBoundsException if {@code start < 0 || start > original.length}\n     * @throws IllegalArgumentException if {@code start > end}\n     * @throws NullPointerException if {@code original == null}\n     * @throws ArrayStoreException if a value in {@code original} is incompatible with T\n     * @since 1.6\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T, U> T[] copyOfRange(U[] original, int start, int end, Class<? extends T[]> newType) {\n        if (start > end) {\n            throw new IllegalArgumentException();\n        }\n        int originalLength = original.length;\n        if (start < 0 || start > originalLength) {\n            throw new ArrayIndexOutOfBoundsException();\n        }\n        int resultLength = end - start;\n        int copyLength = Math.min(resultLength, originalLength - start);\n        T[] result = (T[]) Array.newInstance(newType.getComponentType(), resultLength);\n        System.arraycopy(original, start, result, 0, copyLength);\n        return result;\n    }\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/core/AsyncTask.java",
    "content": "package net.tsz.afinal.core;\n\nimport android.os.Handler;\nimport android.os.Message;\nimport android.os.Process;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CancellationException;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.FutureTask;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * 拷贝 https://android.googlesource.com/platform/frameworks/base/+/jb-release/\n * core/java/android/os/AsyncTask.java\n * 修改了线程池属性，让并发线程按顺序执行\n * @author michael\n *\n * @param <Params>\n * @param <Progress>\n * @param <Result>\n */\npublic abstract class AsyncTask<Params, Progress, Result> {\n    private static final String LOG_TAG = \"AsyncTask\";\n\n    private static final int CORE_POOL_SIZE = 5;\n    private static final int MAXIMUM_POOL_SIZE = 128;\n    private static final int KEEP_ALIVE = 1;\n\n    private static final ThreadFactory  sThreadFactory = new ThreadFactory() {\n        private final AtomicInteger mCount = new AtomicInteger(1);\n        public Thread newThread(Runnable r) {\n        \tThread tread = new Thread(r, \"AsyncTask #\" + mCount.getAndIncrement());\n        \ttread.setPriority(Thread.NORM_PRIORITY - 1);\n            return tread;\n        }\n    };\n\n    private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(10);\n\n    /**\n     * An {@link Executor} that can be used to execute tasks in parallel.\n     */\n    public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,\n            TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory,\n            new ThreadPoolExecutor.DiscardOldestPolicy());\n    \n\n    /**\n     * An {@link Executor} that executes tasks one at a time in serial\n     * order.  This serialization is global to a particular process.\n     */\n    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();\n\n    public static final Executor DUAL_THREAD_EXECUTOR =Executors.newFixedThreadPool(3, sThreadFactory);\n\n    private static final int MESSAGE_POST_RESULT = 0x1;\n    private static final int MESSAGE_POST_PROGRESS = 0x2;\n\n    private static final InternalHandler sHandler = new InternalHandler();\n\n    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;\n    private final WorkerRunnable<Params, Result> mWorker;\n    private final FutureTask<Result> mFuture;\n\n    private volatile Status mStatus = Status.PENDING;\n\n    private final AtomicBoolean mCancelled = new AtomicBoolean();\n    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();\n\n    private static class SerialExecutor implements Executor {\n        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();\n        Runnable mActive;\n\n        public synchronized void execute(final Runnable r) {\n            mTasks.offer(new Runnable() {\n                public void run() {\n                    try {\n                        r.run();\n                    } finally {\n                        scheduleNext();\n                    }\n                }\n            });\n            if (mActive == null) {\n                scheduleNext();\n            }\n        }\n\n        protected synchronized void scheduleNext() {\n            if ((mActive = mTasks.poll()) != null) {\n                THREAD_POOL_EXECUTOR.execute(mActive);\n            }\n        }\n    }\n\n    /**\n     * Indicates the current status of the task. Each status will be set only once\n     * during the lifetime of a task.\n     */\n    public enum Status {\n        /**\n         * Indicates that the task has not been executed yet.\n         */\n        PENDING,\n        /**\n         * Indicates that the task is running.\n         */\n        RUNNING,\n        /**\n         * Indicates that {@link AsyncTask#onPostExecute} has finished.\n         */\n        FINISHED,\n    }\n\n    /** @hide Used to force static handler to be created. */\n    public static void init() {\n        sHandler.getLooper();\n    }\n\n    /** @hide */\n    public static void setDefaultExecutor(Executor exec) {\n        sDefaultExecutor = exec;\n    }\n\n    /**\n     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.\n     */\n    public AsyncTask() {\n        mWorker = new WorkerRunnable<Params, Result>() {\n            public Result call() throws Exception {\n                mTaskInvoked.set(true);\n\n                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);\n                //noinspection unchecked\n                return postResult(doInBackground(mParams));\n            }\n        };\n\n        mFuture = new FutureTask<Result>(mWorker) {\n            @Override\n            protected void done() {\n                try {\n                    postResultIfNotInvoked(get());\n                } catch (InterruptedException e) {\n                    android.util.Log.w(LOG_TAG, e);\n                } catch (ExecutionException e) {\n                    throw new RuntimeException(\"An error occured while executing doInBackground()\",\n                            e.getCause());\n                } catch (CancellationException e) {\n                    postResultIfNotInvoked(null);\n                }\n            }\n        };\n    }\n\n    private void postResultIfNotInvoked(Result result) {\n        final boolean wasTaskInvoked = mTaskInvoked.get();\n        if (!wasTaskInvoked) {\n            postResult(result);\n        }\n    }\n\n    private Result postResult(Result result) {\n        @SuppressWarnings(\"unchecked\")\n        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,\n                new AsyncTaskResult<Result>(this, result));\n        message.sendToTarget();\n        return result;\n    }\n\n    /**\n     * Returns the current status of this task.\n     *\n     * @return The current status.\n     */\n    public final Status getStatus() {\n        return mStatus;\n    }\n\n    /**\n     * Override this method to perform a computation on a background thread. The\n     * specified parameters are the parameters passed to {@link #execute}\n     * by the caller of this task.\n     *\n     * This method can call {@link #publishProgress} to publish updates\n     * on the UI thread.\n     *\n     * @param params The parameters of the task.\n     *\n     * @return A result, defined by the subclass of this task.\n     *\n     * @see #onPreExecute()\n     * @see #onPostExecute\n     * @see #publishProgress\n     */\n    protected abstract Result doInBackground(Params... params);\n\n    /**\n     * Runs on the UI thread before {@link #doInBackground}.\n     *\n     * @see #onPostExecute\n     * @see #doInBackground\n     */\n    protected void onPreExecute() {\n    }\n\n    /**\n     * <p>Runs on the UI thread after {@link #doInBackground}. The\n     * specified result is the value returned by {@link #doInBackground}.</p>\n     *\n     * <p>This method won't be invoked if the task was cancelled.</p>\n     *\n     * @param result The result of the operation computed by {@link #doInBackground}.\n     *\n     * @see #onPreExecute\n     * @see #doInBackground\n     * @see #onCancelled(Object)\n     */\n    protected void onPostExecute(Result result) {\n    }\n\n    /**\n     * Runs on the UI thread after {@link #publishProgress} is invoked.\n     * The specified values are the values passed to {@link #publishProgress}.\n     *\n     * @param values The values indicating progress.\n     *\n     * @see #publishProgress\n     * @see #doInBackground\n     */\n    protected void onProgressUpdate(Progress... values) {\n    }\n\n    /**\n     * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and\n     * {@link #doInBackground(Object[])} has finished.</p>\n     *\n     * <p>The default implementation simply invokes {@link #onCancelled()} and\n     * ignores the result. If you write your own implementation, do not call\n     * <code>super.onCancelled(result)</code>.</p>\n     *\n     * @param result The result, if any, computed in\n     *               {@link #doInBackground(Object[])}, can be null\n     *\n     * @see #cancel(boolean)\n     * @see #isCancelled()\n     */\n    protected void onCancelled(Result result) {\n        onCancelled();\n    }\n\n    /**\n     * <p>Applications should preferably override {@link #onCancelled(Object)}.\n     * This method is invoked by the default implementation of\n     * {@link #onCancelled(Object)}.</p>\n     *\n     * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and\n     * {@link #doInBackground(Object[])} has finished.</p>\n     *\n     * @see #onCancelled(Object)\n     * @see #cancel(boolean)\n     * @see #isCancelled()\n     */\n    protected void onCancelled() {\n    }\n\n    /**\n     * Returns <tt>true</tt> if this task was cancelled before it completed\n     * normally. If you are calling {@link #cancel(boolean)} on the task,\n     * the value returned by this method should be checked periodically from\n     * {@link #doInBackground(Object[])} to end the task as soon as possible.\n     *\n     * @return <tt>true</tt> if task was cancelled before it completed\n     *\n     * @see #cancel(boolean)\n     */\n    public final boolean isCancelled() {\n        return mCancelled.get();\n    }\n\n    /**\n     * <p>Attempts to cancel execution of this task.  This attempt will\n     * fail if the task has already completed, already been cancelled,\n     * or could not be cancelled for some other reason. If successful,\n     * and this task has not started when <tt>cancel</tt> is called,\n     * this task should never run. If the task has already started,\n     * then the <tt>mayInterruptIfRunning</tt> parameter determines\n     * whether the thread executing this task should be interrupted in\n     * an attempt to stop the task.</p>\n     *\n     * <p>Calling this method will result in {@link #onCancelled(Object)} being\n     * invoked on the UI thread after {@link #doInBackground(Object[])}\n     * returns. Calling this method guarantees that {@link #onPostExecute(Object)}\n     * is never invoked. After invoking this method, you should check the\n     * value returned by {@link #isCancelled()} periodically from\n     * {@link #doInBackground(Object[])} to finish the task as early as\n     * possible.</p>\n     *\n     * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this\n     *        task should be interrupted; otherwise, in-progress tasks are allowed\n     *        to complete.\n     *\n     * @return <tt>false</tt> if the task could not be cancelled,\n     *         typically because it has already completed normally;\n     *         <tt>true</tt> otherwise\n     *\n     * @see #isCancelled()\n     * @see #onCancelled(Object)\n     */\n    public final boolean cancel(boolean mayInterruptIfRunning) {\n        mCancelled.set(true);\n        return mFuture.cancel(mayInterruptIfRunning);\n    }\n\n    /**\n     * Waits if necessary for the computation to complete, and then\n     * retrieves its result.\n     *\n     * @return The computed result.\n     *\n     * @throws CancellationException If the computation was cancelled.\n     * @throws ExecutionException If the computation threw an exception.\n     * @throws InterruptedException If the current thread was interrupted\n     *         while waiting.\n     */\n    public final Result get() throws InterruptedException, ExecutionException {\n        return mFuture.get();\n    }\n\n    /**\n     * Waits if necessary for at most the given time for the computation\n     * to complete, and then retrieves its result.\n     *\n     * @param timeout Time to wait before cancelling the operation.\n     * @param unit The time unit for the timeout.\n     *\n     * @return The computed result.\n     *\n     * @throws CancellationException If the computation was cancelled.\n     * @throws ExecutionException If the computation threw an exception.\n     * @throws InterruptedException If the current thread was interrupted\n     *         while waiting.\n     * @throws TimeoutException If the wait timed out.\n     */\n    public final Result get(long timeout, TimeUnit unit) throws InterruptedException,\n            ExecutionException, TimeoutException {\n        return mFuture.get(timeout, unit);\n    }\n\n    /**\n     * Executes the task with the specified parameters. The task returns\n     * itself (this) so that the caller can keep a reference to it.\n     *\n     * <p>Note: this function schedules the task on a queue for a single background\n     * thread or pool of threads depending on the platform version.  When first\n     * introduced, AsyncTasks were executed serially on a single background thread.\n     * Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed\n     * to a pool of threads allowing multiple tasks to operate in parallel. Starting\n     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being\n     * executed on a single thread to avoid common application errors caused\n     * by parallel execution.  If you truly want parallel execution, you can use\n     * the {@link #executeOnExecutor} version of this method\n     * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings\n     * on its use.\n     *\n     * <p>This method must be invoked on the UI thread.\n     *\n     * @param params The parameters of the task.\n     *\n     * @return This instance of AsyncTask.\n     *\n     * @throws IllegalStateException If {@link #getStatus()} returns either\n     *         {@link Status#RUNNING} or {@link Status#FINISHED}.\n     *\n     * @see #executeOnExecutor(Executor, Object[])\n     * @see #execute(Runnable)\n     */\n    public final AsyncTask<Params, Progress, Result> execute(Params... params) {\n        return executeOnExecutor(sDefaultExecutor, params);\n    }\n\n    /**\n     * Executes the task with the specified parameters. The task returns\n     * itself (this) so that the caller can keep a reference to it.\n     *\n     * <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to\n     * allow multiple tasks to run in parallel on a pool of threads managed by\n     * AsyncTask, however you can also use your own {@link Executor} for custom\n     * behavior.\n     *\n     * <p><em>Warning:</em> Allowing multiple tasks to run in parallel from\n     * a thread pool is generally <em>not</em> what one wants, because the order\n     * of their operation is not defined.  For example, if these tasks are used\n     * to modify any state in common (such as writing a file due to a button click),\n     * there are no guarantees on the order of the modifications.\n     * Without careful work it is possible in rare cases for the newer version\n     * of the data to be over-written by an older one, leading to obscure data\n     * loss and stability issues.  Such changes are best\n     * executed in serial; to guarantee such work is serialized regardless of\n     * platform version you can use this function with {@link #SERIAL_EXECUTOR}.\n     *\n     * <p>This method must be invoked on the UI thread.\n     *\n     * @param exec The executor to use.  {@link #THREAD_POOL_EXECUTOR} is available as a\n     *              convenient process-wide thread pool for tasks that are loosely coupled.\n     * @param params The parameters of the task.\n     *\n     * @return This instance of AsyncTask.\n     *\n     * @throws IllegalStateException If {@link #getStatus()} returns either\n     *         {@link Status#RUNNING} or {@link Status#FINISHED}.\n     *\n     * @see #execute(Object[])\n     */\n    @SuppressWarnings(\"incomplete-switch\")\n\tpublic final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,\n            Params... params) {\n        if (mStatus != Status.PENDING) {\n            switch (mStatus) {\n                case RUNNING:\n                    throw new IllegalStateException(\"Cannot execute task:\"\n                            + \" the task is already running.\");\n                case FINISHED:\n                    throw new IllegalStateException(\"Cannot execute task:\"\n                            + \" the task has already been executed \"\n                            + \"(a task can be executed only once)\");\n            }\n        }\n\n        mStatus = Status.RUNNING;\n\n        onPreExecute();\n\n        mWorker.mParams = params;\n        exec.execute(mFuture);\n\n        return this;\n    }\n\n    /**\n     * Convenience version of {@link #execute(Object...)} for use with\n     * a simple Runnable object. See {@link #execute(Object[])} for more\n     * information on the order of execution.\n     *\n     * @see #execute(Object[])\n     * @see #executeOnExecutor(Executor, Object[])\n     */\n    public static void execute(Runnable runnable) {\n        sDefaultExecutor.execute(runnable);\n    }\n\n    /**\n     * This method can be invoked from {@link #doInBackground} to\n     * publish updates on the UI thread while the background computation is\n     * still running. Each call to this method will trigger the execution of\n     * {@link #onProgressUpdate} on the UI thread.\n     *\n     * {@link #onProgressUpdate} will note be called if the task has been\n     * canceled.\n     *\n     * @param values The progress values to update the UI with.\n     *\n     * @see #onProgressUpdate\n     * @see #doInBackground\n     */\n    protected final void publishProgress(Progress... values) {\n        if (!isCancelled()) {\n            sHandler.obtainMessage(MESSAGE_POST_PROGRESS,\n                    new AsyncTaskResult<Progress>(this, values)).sendToTarget();\n        }\n    }\n\n    private void finish(Result result) {\n        if (isCancelled()) {\n            onCancelled(result);\n        } else {\n            onPostExecute(result);\n        }\n        mStatus = Status.FINISHED;\n    }\n\n    private static class InternalHandler extends Handler {\n        @SuppressWarnings(\"unchecked\")\n\t\t@Override\n        public void handleMessage(Message msg) {\n            @SuppressWarnings(\"rawtypes\")\n\t\t\tAsyncTaskResult result = (AsyncTaskResult) msg.obj;\n            switch (msg.what) {\n                case MESSAGE_POST_RESULT:\n                    result.mTask.finish(result.mData[0]);\n                    break;\n                case MESSAGE_POST_PROGRESS:\n                    result.mTask.onProgressUpdate(result.mData);\n                    break;\n            }\n        }\n    }\n\n    private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {\n        Params[] mParams;\n    }\n\n    private static class AsyncTaskResult<Data> {\n        @SuppressWarnings(\"rawtypes\")\n\t\tfinal AsyncTask mTask;\n        final Data[] mData;\n\n        AsyncTaskResult(@SuppressWarnings(\"rawtypes\") AsyncTask task, Data... data) {\n            mTask = task;\n            mData = data;\n        }\n    }\n}"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/core/Deque.java",
    "content": "/*\n * Written by Doug Lea and Josh Bloch with assistance from members of\n * JCP JSR-166 Expert Group and released to the public domain, as explained\n * at http://creativecommons.org/licenses/publicdomain\n */\n\npackage net.tsz.afinal.core;\n\nimport java.util.Iterator;\n\n// BEGIN android-note\n// removed link to collections framework docs\n// changed {@link #offer(Object)} to {@link #offer} to satisfy DroidDoc\n// END android-note\n\n/**\n * A linear collection that supports element insertion and removal at\n * both ends.  The name <i>deque</i> is short for \"double ended queue\"\n * and is usually pronounced \"deck\".  Most <tt>Deque</tt>\n * implementations place no fixed limits on the number of elements\n * they may contain, but this interface supports capacity-restricted\n * deques as well as those with no fixed size limit.\n *\n * <p>This interface defines methods to access the elements at both\n * ends of the deque.  Methods are provided to insert, remove, and\n * examine the element.  Each of these methods exists in two forms:\n * one throws an exception if the operation fails, the other returns a\n * special value (either <tt>null</tt> or <tt>false</tt>, depending on\n * the operation).  The latter form of the insert operation is\n * designed specifically for use with capacity-restricted\n * <tt>Deque</tt> implementations; in most implementations, insert\n * operations cannot fail.\n *\n * <p>The twelve methods described above are summarized in the\n * following table:\n *\n * <p>\n * <table BORDER CELLPADDING=3 CELLSPACING=1>\n *  <tr>\n *    <td></td>\n *    <td ALIGN=CENTER COLSPAN = 2> <b>First Element (Head)</b></td>\n *    <td ALIGN=CENTER COLSPAN = 2> <b>Last Element (Tail)</b></td>\n *  </tr>\n *  <tr>\n *    <td></td>\n *    <td ALIGN=CENTER><em>Throws exception</em></td>\n *    <td ALIGN=CENTER><em>Special value</em></td>\n *    <td ALIGN=CENTER><em>Throws exception</em></td>\n *    <td ALIGN=CENTER><em>Special value</em></td>\n *  </tr>\n *  <tr>\n *    <td><b>Insert</b></td>\n *    <td>{@link #addFirst addFirst(e)}</td>\n *    <td>{@link #offerFirst offerFirst(e)}</td>\n *    <td>{@link #addLast addLast(e)}</td>\n *    <td>{@link #offerLast offerLast(e)}</td>\n *  </tr>\n *  <tr>\n *    <td><b>Remove</b></td>\n *    <td>{@link #removeFirst removeFirst()}</td>\n *    <td>{@link #pollFirst pollFirst()}</td>\n *    <td>{@link #removeLast removeLast()}</td>\n *    <td>{@link #pollLast pollLast()}</td>\n *  </tr>\n *  <tr>\n *    <td><b>Examine</b></td>\n *    <td>{@link #getFirst getFirst()}</td>\n *    <td>{@link #peekFirst peekFirst()}</td>\n *    <td>{@link #getLast getLast()}</td>\n *    <td>{@link #peekLast peekLast()}</td>\n *  </tr>\n * </table>\n *\n * <p>This interface extends the {@link Queue} interface.  When a deque is\n * used as a queue, FIFO (First-In-First-Out) behavior results.  Elements are\n * added at the end of the deque and removed from the beginning.  The methods\n * inherited from the <tt>Queue</tt> interface are precisely equivalent to\n * <tt>Deque</tt> methods as indicated in the following table:\n *\n * <p>\n * <table BORDER CELLPADDING=3 CELLSPACING=1>\n *  <tr>\n *    <td ALIGN=CENTER> <b><tt>Queue</tt> Method</b></td>\n *    <td ALIGN=CENTER> <b>Equivalent <tt>Deque</tt> Method</b></td>\n *  </tr>\n *  <tr>\n *    <td>{@link java.util.Queue#add add(e)}</td>\n *    <td>{@link #addLast addLast(e)}</td>\n *  </tr>\n *  <tr>\n *    <td>{@link java.util.Queue#offer offer(e)}</td>\n *    <td>{@link #offerLast offerLast(e)}</td>\n *  </tr>\n *  <tr>\n *    <td>{@link java.util.Queue#remove remove()}</td>\n *    <td>{@link #removeFirst removeFirst()}</td>\n *  </tr>\n *  <tr>\n *    <td>{@link java.util.Queue#poll poll()}</td>\n *    <td>{@link #pollFirst pollFirst()}</td>\n *  </tr>\n *  <tr>\n *    <td>{@link java.util.Queue#element element()}</td>\n *    <td>{@link #getFirst getFirst()}</td>\n *  </tr>\n *  <tr>\n *    <td>{@link java.util.Queue#peek peek()}</td>\n *    <td>{@link #peek peekFirst()}</td>\n *  </tr>\n * </table>\n *\n * <p>Deques can also be used as LIFO (Last-In-First-Out) stacks.  This\n * interface should be used in preference to the legacy {@link Stack} class.\n * When a deque is used as a stack, elements are pushed and popped from the\n * beginning of the deque.  Stack methods are precisely equivalent to\n * <tt>Deque</tt> methods as indicated in the table below:\n *\n * <p>\n * <table BORDER CELLPADDING=3 CELLSPACING=1>\n *  <tr>\n *    <td ALIGN=CENTER> <b>Stack Method</b></td>\n *    <td ALIGN=CENTER> <b>Equivalent <tt>Deque</tt> Method</b></td>\n *  </tr>\n *  <tr>\n *    <td>{@link #push push(e)}</td>\n *    <td>{@link #addFirst addFirst(e)}</td>\n *  </tr>\n *  <tr>\n *    <td>{@link #pop pop()}</td>\n *    <td>{@link #removeFirst removeFirst()}</td>\n *  </tr>\n *  <tr>\n *    <td>{@link #peek peek()}</td>\n *    <td>{@link #peekFirst peekFirst()}</td>\n *  </tr>\n * </table>\n *\n * <p>Note that the {@link #peek peek} method works equally well when\n * a deque is used as a queue or a stack; in either case, elements are\n * drawn from the beginning of the deque.\n *\n * <p>This interface provides two methods to remove interior\n * elements, {@link #removeFirstOccurrence removeFirstOccurrence} and\n * {@link #removeLastOccurrence removeLastOccurrence}.\n *\n * <p>Unlike the {@link List} interface, this interface does not\n * provide support for indexed access to elements.\n *\n * <p>While <tt>Deque</tt> implementations are not strictly required\n * to prohibit the insertion of null elements, they are strongly\n * encouraged to do so.  Users of any <tt>Deque</tt> implementations\n * that do allow null elements are strongly encouraged <i>not</i> to\n * take advantage of the ability to insert nulls.  This is so because\n * <tt>null</tt> is used as a special return value by various methods\n * to indicated that the deque is empty.\n *\n * <p><tt>Deque</tt> implementations generally do not define\n * element-based versions of the <tt>equals</tt> and <tt>hashCode</tt>\n * methods, but instead inherit the identity-based versions from class\n * <tt>Object</tt>.\n *\n * @author Doug Lea\n * @author Josh Bloch\n * @since  1.6\n * @param <E> the type of elements held in this collection\n */\n\npublic interface Deque<E> extends Queue<E> {\n    /**\n     * Inserts the specified element at the front of this deque if it is\n     * possible to do so immediately without violating capacity restrictions.\n     * When using a capacity-restricted deque, it is generally preferable to\n     * use method {@link #offerFirst}.\n     *\n     * @param e the element to add\n     * @throws IllegalStateException if the element cannot be added at this\n     *         time due to capacity restrictions\n     * @throws ClassCastException if the class of the specified element\n     *         prevents it from being added to this deque\n     * @throws NullPointerException if the specified element is null and this\n     *         deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *         element prevents it from being added to this deque\n     */\n    void addFirst(E e);\n\n    /**\n     * Inserts the specified element at the end of this deque if it is\n     * possible to do so immediately without violating capacity restrictions.\n     * When using a capacity-restricted deque, it is generally preferable to\n     * use method {@link #offerLast}.\n     *\n     * <p>This method is equivalent to {@link #add}.\n     *\n     * @param e the element to add\n     * @throws IllegalStateException if the element cannot be added at this\n     *         time due to capacity restrictions\n     * @throws ClassCastException if the class of the specified element\n     *         prevents it from being added to this deque\n     * @throws NullPointerException if the specified element is null and this\n     *         deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *         element prevents it from being added to this deque\n     */\n    void addLast(E e);\n\n    /**\n     * Inserts the specified element at the front of this deque unless it would\n     * violate capacity restrictions.  When using a capacity-restricted deque,\n     * this method is generally preferable to the {@link #addFirst} method,\n     * which can fail to insert an element only by throwing an exception.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> if the element was added to this deque, else\n     *         <tt>false</tt>\n     * @throws ClassCastException if the class of the specified element\n     *         prevents it from being added to this deque\n     * @throws NullPointerException if the specified element is null and this\n     *         deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *         element prevents it from being added to this deque\n     */\n    boolean offerFirst(E e);\n\n    /**\n     * Inserts the specified element at the end of this deque unless it would\n     * violate capacity restrictions.  When using a capacity-restricted deque,\n     * this method is generally preferable to the {@link #addLast} method,\n     * which can fail to insert an element only by throwing an exception.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> if the element was added to this deque, else\n     *         <tt>false</tt>\n     * @throws ClassCastException if the class of the specified element\n     *         prevents it from being added to this deque\n     * @throws NullPointerException if the specified element is null and this\n     *         deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *         element prevents it from being added to this deque\n     */\n    boolean offerLast(E e);\n\n    /**\n     * Retrieves and removes the first element of this deque.  This method\n     * differs from {@link #pollFirst pollFirst} only in that it throws an\n     * exception if this deque is empty.\n     *\n     * @return the head of this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E removeFirst();\n\n    /**\n     * Retrieves and removes the last element of this deque.  This method\n     * differs from {@link #pollLast pollLast} only in that it throws an\n     * exception if this deque is empty.\n     *\n     * @return the tail of this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E removeLast();\n\n    /**\n     * Retrieves and removes the first element of this deque,\n     * or returns <tt>null</tt> if this deque is empty.\n     *\n     * @return the head of this deque, or <tt>null</tt> if this deque is empty\n     */\n    E pollFirst();\n\n    /**\n     * Retrieves and removes the last element of this deque,\n     * or returns <tt>null</tt> if this deque is empty.\n     *\n     * @return the tail of this deque, or <tt>null</tt> if this deque is empty\n     */\n    E pollLast();\n\n    /**\n     * Retrieves, but does not remove, the first element of this deque.\n     *\n     * This method differs from {@link #peekFirst peekFirst} only in that it\n     * throws an exception if this deque is empty.\n     *\n     * @return the head of this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E getFirst();\n\n    /**\n     * Retrieves, but does not remove, the last element of this deque.\n     * This method differs from {@link #peekLast peekLast} only in that it\n     * throws an exception if this deque is empty.\n     *\n     * @return the tail of this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E getLast();\n\n    /**\n     * Retrieves, but does not remove, the first element of this deque,\n     * or returns <tt>null</tt> if this deque is empty.\n     *\n     * @return the head of this deque, or <tt>null</tt> if this deque is empty\n     */\n    E peekFirst();\n\n    /**\n     * Retrieves, but does not remove, the last element of this deque,\n     * or returns <tt>null</tt> if this deque is empty.\n     *\n     * @return the tail of this deque, or <tt>null</tt> if this deque is empty\n     */\n    E peekLast();\n\n    /**\n     * Removes the first occurrence of the specified element from this deque.\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the first element <tt>e</tt> such that\n     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>\n     * (if such an element exists).\n     * Returns <tt>true</tt> if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     *\n     * @param o element to be removed from this deque, if present\n     * @return <tt>true</tt> if an element was removed as a result of this call\n     * @throws ClassCastException if the class of the specified element\n     *         is incompatible with this deque (optional)\n     * @throws NullPointerException if the specified element is null and this\n     *         deque does not permit null elements (optional)\n     */\n    boolean removeFirstOccurrence(Object o);\n\n    /**\n     * Removes the last occurrence of the specified element from this deque.\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the last element <tt>e</tt> such that\n     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>\n     * (if such an element exists).\n     * Returns <tt>true</tt> if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     *\n     * @param o element to be removed from this deque, if present\n     * @return <tt>true</tt> if an element was removed as a result of this call\n     * @throws ClassCastException if the class of the specified element\n     *         is incompatible with this deque (optional)\n     * @throws NullPointerException if the specified element is null and this\n     *         deque does not permit null elements (optional)\n     */\n    boolean removeLastOccurrence(Object o);\n\n    // *** Queue methods ***\n\n    /**\n     * Inserts the specified element into the queue represented by this deque\n     * (in other words, at the tail of this deque) if it is possible to do so\n     * immediately without violating capacity restrictions, returning\n     * <tt>true</tt> upon success and throwing an\n     * <tt>IllegalStateException</tt> if no space is currently available.\n     * When using a capacity-restricted deque, it is generally preferable to\n     * use {@link #offer offer}.\n     *\n     * <p>This method is equivalent to {@link #addLast}.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> (as specified by {@link Collection#add})\n     * @throws IllegalStateException if the element cannot be added at this\n     *         time due to capacity restrictions\n     * @throws ClassCastException if the class of the specified element\n     *         prevents it from being added to this deque\n     * @throws NullPointerException if the specified element is null and this\n     *         deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *         element prevents it from being added to this deque\n     */\n    boolean add(E e);\n\n    /**\n     * Inserts the specified element into the queue represented by this deque\n     * (in other words, at the tail of this deque) if it is possible to do so\n     * immediately without violating capacity restrictions, returning\n     * <tt>true</tt> upon success and <tt>false</tt> if no space is currently\n     * available.  When using a capacity-restricted deque, this method is\n     * generally preferable to the {@link #add} method, which can fail to\n     * insert an element only by throwing an exception.\n     *\n     * <p>This method is equivalent to {@link #offerLast}.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> if the element was added to this deque, else\n     *         <tt>false</tt>\n     * @throws ClassCastException if the class of the specified element\n     *         prevents it from being added to this deque\n     * @throws NullPointerException if the specified element is null and this\n     *         deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *         element prevents it from being added to this deque\n     */\n    boolean offer(E e);\n\n    /**\n     * Retrieves and removes the head of the queue represented by this deque\n     * (in other words, the first element of this deque).\n     * This method differs from {@link #poll poll} only in that it throws an\n     * exception if this deque is empty.\n     *\n     * <p>This method is equivalent to {@link #removeFirst()}.\n     *\n     * @return the head of the queue represented by this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E remove();\n\n    /**\n     * Retrieves and removes the head of the queue represented by this deque\n     * (in other words, the first element of this deque), or returns\n     * <tt>null</tt> if this deque is empty.\n     *\n     * <p>This method is equivalent to {@link #pollFirst()}.\n     *\n     * @return the first element of this deque, or <tt>null</tt> if\n     *         this deque is empty\n     */\n    E poll();\n\n    /**\n     * Retrieves, but does not remove, the head of the queue represented by\n     * this deque (in other words, the first element of this deque).\n     * This method differs from {@link #peek peek} only in that it throws an\n     * exception if this deque is empty.\n     *\n     * <p>This method is equivalent to {@link #getFirst()}.\n     *\n     * @return the head of the queue represented by this deque\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E element();\n\n    /**\n     * Retrieves, but does not remove, the head of the queue represented by\n     * this deque (in other words, the first element of this deque), or\n     * returns <tt>null</tt> if this deque is empty.\n     *\n     * <p>This method is equivalent to {@link #peekFirst()}.\n     *\n     * @return the head of the queue represented by this deque, or\n     *         <tt>null</tt> if this deque is empty\n     */\n    E peek();\n\n\n    // *** Stack methods ***\n\n    /**\n     * Pushes an element onto the stack represented by this deque (in other\n     * words, at the head of this deque) if it is possible to do so\n     * immediately without violating capacity restrictions, returning\n     * <tt>true</tt> upon success and throwing an\n     * <tt>IllegalStateException</tt> if no space is currently available.\n     *\n     * <p>This method is equivalent to {@link #addFirst}.\n     *\n     * @param e the element to push\n     * @throws IllegalStateException if the element cannot be added at this\n     *         time due to capacity restrictions\n     * @throws ClassCastException if the class of the specified element\n     *         prevents it from being added to this deque\n     * @throws NullPointerException if the specified element is null and this\n     *         deque does not permit null elements\n     * @throws IllegalArgumentException if some property of the specified\n     *         element prevents it from being added to this deque\n     */\n    void push(E e);\n\n    /**\n     * Pops an element from the stack represented by this deque.  In other\n     * words, removes and returns the first element of this deque.\n     *\n     * <p>This method is equivalent to {@link #removeFirst()}.\n     *\n     * @return the element at the front of this deque (which is the top\n     *         of the stack represented by this deque)\n     * @throws NoSuchElementException if this deque is empty\n     */\n    E pop();\n\n\n    // *** Collection methods ***\n\n    /**\n     * Removes the first occurrence of the specified element from this deque.\n     * If the deque does not contain the element, it is unchanged.\n     * More formally, removes the first element <tt>e</tt> such that\n     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>\n     * (if such an element exists).\n     * Returns <tt>true</tt> if this deque contained the specified element\n     * (or equivalently, if this deque changed as a result of the call).\n     *\n     * <p>This method is equivalent to {@link #removeFirstOccurrence}.\n     *\n     * @param o element to be removed from this deque, if present\n     * @return <tt>true</tt> if an element was removed as a result of this call\n     * @throws ClassCastException if the class of the specified element\n     *         is incompatible with this deque (optional)\n     * @throws NullPointerException if the specified element is null and this\n     *         deque does not permit null elements (optional)\n     */\n    boolean remove(Object o);\n\n    /**\n     * Returns <tt>true</tt> if this deque contains the specified element.\n     * More formally, returns <tt>true</tt> if and only if this deque contains\n     * at least one element <tt>e</tt> such that\n     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.\n     *\n     * @param o element whose presence in this deque is to be tested\n     * @return <tt>true</tt> if this deque contains the specified element\n     * @throws ClassCastException if the type of the specified element\n     *         is incompatible with this deque (optional)\n     * @throws NullPointerException if the specified element is null and this\n     *         deque does not permit null elements (optional)\n     */\n    boolean contains(Object o);\n\n    /**\n     * Returns the number of elements in this deque.\n     *\n     * @return the number of elements in this deque\n     */\n    public int size();\n\n    /**\n     * Returns an iterator over the elements in this deque in proper sequence.\n     * The elements will be returned in order from first (head) to last (tail).\n     *\n     * @return an iterator over the elements in this deque in proper sequence\n     */\n    Iterator<E> iterator();\n\n    /**\n     * Returns an iterator over the elements in this deque in reverse\n     * sequential order.  The elements will be returned in order from\n     * last (tail) to first (head).\n     *\n     * @return an iterator over the elements in this deque in reverse\n     * sequence\n     */\n    Iterator<E> descendingIterator();\n\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/core/FileNameGenerator.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.core;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\npublic class FileNameGenerator {\n\t  \n\t\n    public static String generator(String key) {\n        String cacheKey;\n        try {\n            final MessageDigest mDigest = MessageDigest.getInstance(\"MD5\");\n            mDigest.update(key.getBytes());\n            cacheKey = bytesToHexString(mDigest.digest());\n        } catch (NoSuchAlgorithmException e) {\n            cacheKey = String.valueOf(key.hashCode());\n        }\n        return cacheKey;\n    }\n\n    private static String bytesToHexString(byte[] bytes) {\n        // http://stackoverflow.com/questions/332079\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < bytes.length; i++) {\n            String hex = Integer.toHexString(0xFF & bytes[i]);\n            if (hex.length() == 1) {\n                sb.append('0');\n            }\n            sb.append(hex);\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/core/Queue.java",
    "content": "/*\n * Written by Doug Lea with assistance from members of JCP JSR-166\n * Expert Group and released to the public domain, as explained at\n * http://creativecommons.org/licenses/publicdomain\n */\n\npackage net.tsz.afinal.core;\n\nimport java.util.Collection;\n\n// BEGIN android-note\n// removed link to collections framework docs\n// END android-note\n\n/**\n * A collection designed for holding elements prior to processing.\n * Besides basic {@link Collection Collection} operations,\n * queues provide additional insertion, extraction, and inspection\n * operations.  Each of these methods exists in two forms: one throws\n * an exception if the operation fails, the other returns a special\n * value (either <tt>null</tt> or <tt>false</tt>, depending on the\n * operation).  The latter form of the insert operation is designed\n * specifically for use with capacity-restricted <tt>Queue</tt>\n * implementations; in most implementations, insert operations cannot\n * fail.\n *\n * <p>\n * <table BORDER CELLPADDING=3 CELLSPACING=1>\n *  <tr>\n *    <td></td>\n *    <td ALIGN=CENTER><em>Throws exception</em></td>\n *    <td ALIGN=CENTER><em>Returns special value</em></td>\n *  </tr>\n *  <tr>\n *    <td><b>Insert</b></td>\n *    <td>{@link #add add(e)}</td>\n *    <td>{@link #offer offer(e)}</td>\n *  </tr>\n *  <tr>\n *    <td><b>Remove</b></td>\n *    <td>{@link #remove remove()}</td>\n *    <td>{@link #poll poll()}</td>\n *  </tr>\n *  <tr>\n *    <td><b>Examine</b></td>\n *    <td>{@link #element element()}</td>\n *    <td>{@link #peek peek()}</td>\n *  </tr>\n * </table>\n *\n * <p>Queues typically, but do not necessarily, order elements in a\n * FIFO (first-in-first-out) manner.  Among the exceptions are\n * priority queues, which order elements according to a supplied\n * comparator, or the elements' natural ordering, and LIFO queues (or\n * stacks) which order the elements LIFO (last-in-first-out).\n * Whatever the ordering used, the <em>head</em> of the queue is that\n * element which would be removed by a call to {@link #remove() } or\n * {@link #poll()}.  In a FIFO queue, all new elements are inserted at\n * the <em> tail</em> of the queue. Other kinds of queues may use\n * different placement rules.  Every <tt>Queue</tt> implementation\n * must specify its ordering properties.\n *\n * <p>The {@link #offer offer} method inserts an element if possible,\n * otherwise returning <tt>false</tt>.  This differs from the {@link\n * Collection#add Collection.add} method, which can fail to\n * add an element only by throwing an unchecked exception.  The\n * <tt>offer</tt> method is designed for use when failure is a normal,\n * rather than exceptional occurrence, for example, in fixed-capacity\n * (or &quot;bounded&quot;) queues.\n *\n * <p>The {@link #remove()} and {@link #poll()} methods remove and\n * return the head of the queue.\n * Exactly which element is removed from the queue is a\n * function of the queue's ordering policy, which differs from\n * implementation to implementation. The <tt>remove()</tt> and\n * <tt>poll()</tt> methods differ only in their behavior when the\n * queue is empty: the <tt>remove()</tt> method throws an exception,\n * while the <tt>poll()</tt> method returns <tt>null</tt>.\n *\n * <p>The {@link #element()} and {@link #peek()} methods return, but do\n * not remove, the head of the queue.\n *\n * <p>The <tt>Queue</tt> interface does not define the <i>blocking queue\n * methods</i>, which are common in concurrent programming.  These methods,\n * which wait for elements to appear or for space to become available, are\n * defined in the {@link java.util.concurrent.BlockingQueue} interface, which\n * extends this interface.\n *\n * <p><tt>Queue</tt> implementations generally do not allow insertion\n * of <tt>null</tt> elements, although some implementations, such as\n * {@link LinkedList}, do not prohibit insertion of <tt>null</tt>.\n * Even in the implementations that permit it, <tt>null</tt> should\n * not be inserted into a <tt>Queue</tt>, as <tt>null</tt> is also\n * used as a special return value by the <tt>poll</tt> method to\n * indicate that the queue contains no elements.\n *\n * <p><tt>Queue</tt> implementations generally do not define\n * element-based versions of methods <tt>equals</tt> and\n * <tt>hashCode</tt> but instead inherit the identity based versions\n * from class <tt>Object</tt>, because element-based equality is not\n * always well-defined for queues with the same elements but different\n * ordering properties.\n *\n * @see Collection\n * @see LinkedList\n * @see PriorityQueue\n * @see java.util.concurrent.LinkedBlockingQueue\n * @see java.util.concurrent.BlockingQueue\n * @see java.util.concurrent.ArrayBlockingQueue\n * @see java.util.concurrent.LinkedBlockingQueue\n * @see java.util.concurrent.PriorityBlockingQueue\n * @since 1.5\n * @author Doug Lea\n * @param <E> the type of elements held in this collection\n */\npublic interface Queue<E> extends Collection<E> {\n    /**\n     * Inserts the specified element into this queue if it is possible to do so\n     * immediately without violating capacity restrictions, returning\n     * <tt>true</tt> upon success and throwing an <tt>IllegalStateException</tt>\n     * if no space is currently available.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> (as specified by {@link Collection#add})\n     * @throws IllegalStateException if the element cannot be added at this\n     *         time due to capacity restrictions\n     * @throws ClassCastException if the class of the specified element\n     *         prevents it from being added to this queue\n     * @throws NullPointerException if the specified element is null and\n     *         this queue does not permit null elements\n     * @throws IllegalArgumentException if some property of this element\n     *         prevents it from being added to this queue\n     */\n    boolean add(E e);\n\n    /**\n     * Inserts the specified element into this queue if it is possible to do\n     * so immediately without violating capacity restrictions.\n     * When using a capacity-restricted queue, this method is generally\n     * preferable to {@link #add}, which can fail to insert an element only\n     * by throwing an exception.\n     *\n     * @param e the element to add\n     * @return <tt>true</tt> if the element was added to this queue, else\n     *         <tt>false</tt>\n     * @throws ClassCastException if the class of the specified element\n     *         prevents it from being added to this queue\n     * @throws NullPointerException if the specified element is null and\n     *         this queue does not permit null elements\n     * @throws IllegalArgumentException if some property of this element\n     *         prevents it from being added to this queue\n     */\n    boolean offer(E e);\n\n    /**\n     * Retrieves and removes the head of this queue.  This method differs\n     * from {@link #poll poll} only in that it throws an exception if this\n     * queue is empty.\n     *\n     * @return the head of this queue\n     * @throws NoSuchElementException if this queue is empty\n     */\n    E remove();\n\n    /**\n     * Retrieves and removes the head of this queue,\n     * or returns <tt>null</tt> if this queue is empty.\n     *\n     * @return the head of this queue, or <tt>null</tt> if this queue is empty\n     */\n    E poll();\n\n    /**\n     * Retrieves, but does not remove, the head of this queue.  This method\n     * differs from {@link #peek peek} only in that it throws an exception\n     * if this queue is empty.\n     *\n     * @return the head of this queue\n     * @throws NoSuchElementException if this queue is empty\n     */\n    E element();\n\n    /**\n     * Retrieves, but does not remove, the head of this queue,\n     * or returns <tt>null</tt> if this queue is empty.\n     *\n     * @return the head of this queue, or <tt>null</tt> if this queue is empty\n     */\n    E peek();\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/db/sqlite/CursorUtils.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.db.sqlite;\n\nimport java.util.HashMap;\nimport java.util.Map.Entry;\n\nimport net.tsz.afinal.FinalDb;\nimport net.tsz.afinal.db.table.ManyToOne;\nimport net.tsz.afinal.db.table.OneToMany;\nimport net.tsz.afinal.db.table.Property;\nimport net.tsz.afinal.db.table.TableInfo;\n\n\nimport android.database.Cursor;\n\npublic class CursorUtils {\n\n\tpublic static <T> T getEntity(Cursor cursor, Class<T> clazz,FinalDb db){\n\t\ttry {\n\t\t\tif(cursor!=null ){\n\t\t\t\tTableInfo table = TableInfo.get(clazz);\n\t\t\t\tint columnCount = cursor.getColumnCount();\n\t\t\t\tif(columnCount>0){\n\t\t\t\t\tT  entity = (T) clazz.newInstance();\n\t\t\t\t\tfor(int i=0;i<columnCount;i++){\n\t\t\t\t\t\t\n\t\t\t\t\t\tString column = cursor.getColumnName(i);\n\t\t\t\t\t\t\n\t\t\t\t\t\tProperty property = table.propertyMap.get(column);\n\t\t\t\t\t\tif(property!=null){\n\t\t\t\t\t\t\tproperty.setValue(entity, cursor.getString(i));\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\tif(table.getId().getColumn().equals(column)){\n\t\t\t\t\t\t\t\ttable.getId().setValue(entity,  cursor.getString(i));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n                    /**\n                     * 处理OneToMany的lazyLoad形式\n                     */\n                    for(OneToMany oneToManyProp : table.oneToManyMap.values()){\n                        if(oneToManyProp.getDataType()==OneToManyLazyLoader.class){\n                            OneToManyLazyLoader oneToManyLazyLoader = new OneToManyLazyLoader(entity,clazz,oneToManyProp.getOneClass(),db);\n                            oneToManyProp.setValue(entity,oneToManyLazyLoader);\n                        }\n                    }\n\n                    /**\n                     * 处理ManyToOne的lazyLoad形式\n                     */\n                    for(ManyToOne manyToOneProp : table.manyToOneMap.values()){\n                        if(manyToOneProp.getDataType()==ManyToOneLazyLoader.class){\n                            ManyToOneLazyLoader manyToOneLazyLoader = new ManyToOneLazyLoader(entity,clazz,manyToOneProp.getManyClass(),db);\n                            manyToOneLazyLoader.setFieldValue(cursor.getInt(cursor.getColumnIndex(manyToOneProp.getColumn())));\n                            manyToOneProp.setValue(entity,manyToOneLazyLoader);\n                        }\n                    }\n\t\t\t\t\treturn entity;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\treturn null;\n\t}\n\t\n\t\n\tpublic static DbModel getDbModel(Cursor cursor){\n\t\tif(cursor!=null && cursor.getColumnCount() > 0){\n\t\t\tDbModel model = new DbModel();\n\t\t\tint columnCount = cursor.getColumnCount();\n\t\t\tfor(int i=0;i<columnCount;i++){\n\t\t\t\tmodel.set(cursor.getColumnName(i), cursor.getString(i));\n\t\t\t}\n\t\t\treturn model;\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t\n\tpublic static <T> T dbModel2Entity(DbModel dbModel,Class<?> clazz){\n\t\tif(dbModel!=null){\n\t\t\tHashMap<String, Object> dataMap = dbModel.getDataMap();\n\t\t\ttry {\n\t\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\t\tT  entity = (T) clazz.newInstance();\n\t\t\t\tfor(Entry<String, Object> entry : dataMap.entrySet()){\n\t\t\t\t\tString column = entry.getKey();\n\t\t\t\t\tTableInfo table = TableInfo.get(clazz);\n\t\t\t\t\tProperty property = table.propertyMap.get(column);\n\t\t\t\t\tif(property!=null){\n\t\t\t\t\t\tproperty.setValue(entity, entry.getValue()==null?null:entry.getValue().toString());\n\t\t\t\t\t}else{\n\t\t\t\t\t\tif(table.getId().getColumn().equals(column)){\n\t\t\t\t\t\t\ttable.getId().setValue(entity, entry.getValue()==null?null:entry.getValue().toString());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\treturn entity;\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn null;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/db/sqlite/DbModel.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.db.sqlite;\n\nimport java.util.HashMap;\n\npublic class DbModel {\n\n\tprivate HashMap<String, Object> dataMap = new HashMap<String, Object>();\n\t\n\tpublic Object get(String column){\n\t\treturn dataMap.get(column);\n\t}\n\t\n\tpublic String getString(String column){\n\t\treturn String.valueOf(get(column));\n\t}\n\t\n\tpublic int getInt(String column){\n\t\treturn Integer.valueOf(getString(column));\n\t}\n\t\n\tpublic boolean getBoolean(String column){\n\t\treturn Boolean.valueOf(getString(column));\n\t}\n\t\n\tpublic double getDouble(String column){\n\t\treturn Double.valueOf(getString(column));\n\t}\n\t\n\tpublic float getFloat(String column){\n\t\treturn Float.valueOf(getString(column));\n\t}\n\t\n\tpublic long getLong(String column){\n\t\treturn Long.valueOf(getString(column));\n\t}\n\t\n\tpublic void set(String key,Object value){\n\t\tdataMap.put(key, value);\n\t}\n\t\n\tpublic HashMap<String, Object> getDataMap(){\n\t\treturn dataMap;\n\t}\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/db/sqlite/ManyToOneLazyLoader.java",
    "content": "package net.tsz.afinal.db.sqlite;\n\nimport net.tsz.afinal.FinalDb;\n\n/**\n *\n * 一对多延迟加载类\n * Created by pwy on 13-7-25.\n * @param <O> 宿主实体的class\n * @param <M> 多放实体class\n */\npublic class ManyToOneLazyLoader<M,O> {\n    M manyEntity;\n    Class<M> manyClazz;\n    Class<O> oneClazz;\n    FinalDb db;\n    /**\n     * 用于\n     */\n    private Object fieldValue;\n    public ManyToOneLazyLoader(M manyEntity, Class<M> manyClazz, Class<O> oneClazz, FinalDb db){\n        this.manyEntity = manyEntity;\n        this.manyClazz = manyClazz;\n        this.oneClazz = oneClazz;\n        this.db = db;\n    }\n    O oneEntity;\n    boolean hasLoaded = false;\n\n    /**\n     * 如果数据未加载，则调用loadManyToOne填充数据\n     * @return\n     */\n    public O get(){\n        if(oneEntity==null && !hasLoaded){\n            this.db.loadManyToOne(null,this.manyEntity,this.manyClazz,this.oneClazz);\n            hasLoaded = true;\n        }\n        return oneEntity;\n    }\n    public void set(O value){\n        oneEntity = value;\n    }\n\n    public Object getFieldValue() {\n        return fieldValue;\n    }\n\n    public void setFieldValue(Object fieldValue) {\n        this.fieldValue = fieldValue;\n    }\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/db/sqlite/OneToManyLazyLoader.java",
    "content": "package net.tsz.afinal.db.sqlite;\n\nimport net.tsz.afinal.FinalDb;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n *\n * 一对多延迟加载类\n * Created by pwy on 13-7-25.\n * @param <O> 宿主实体的class\n * @param <M> 多放实体class\n */\npublic class OneToManyLazyLoader<O,M> {\n    O ownerEntity;\n    Class<O> ownerClazz;\n    Class<M> listItemClazz;\n    FinalDb db;\n    public OneToManyLazyLoader(O ownerEntity,Class<O> ownerClazz,Class<M> listItemclazz,FinalDb db){\n        this.ownerEntity = ownerEntity;\n        this.ownerClazz = ownerClazz;\n        this.listItemClazz = listItemclazz;\n        this.db = db;\n    }\n    List<M> entities;\n\n    /**\n     * 如果数据未加载，则调用loadOneToMany填充数据\n     * @return\n     */\n    public List<M> getList(){\n        if(entities==null){\n            this.db.loadOneToMany((O)this.ownerEntity,this.ownerClazz,this.listItemClazz);\n        }\n        if(entities==null){\n            entities =new ArrayList<M>();\n        }\n        return entities;\n    }\n    public void setList(List<M> value){\n        entities = value;\n    }\n\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/db/sqlite/SqlBuilder.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.db.sqlite;\n\nimport android.text.TextUtils;\n\nimport net.tsz.afinal.db.table.Id;\nimport net.tsz.afinal.db.table.KeyValue;\nimport net.tsz.afinal.db.table.ManyToOne;\nimport net.tsz.afinal.db.table.Property;\nimport net.tsz.afinal.db.table.TableInfo;\nimport net.tsz.afinal.exception.DbException;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\npublic class SqlBuilder {\n\t\n\t/**\n\t * 获取插入的sql语句\n\t * @return\n\t */\n\tpublic static SqlInfo buildInsertSql(Object entity){\n\t\t\n\t\tList<KeyValue> keyValueList = getSaveKeyValueListByEntity(entity);\n\t\t\n\t\tStringBuffer strSQL=new StringBuffer();\n\t\tSqlInfo sqlInfo = null;\n\t\tif(keyValueList!=null && keyValueList.size()>0){\n\t\t\t\n\t\t\tsqlInfo = new SqlInfo();\n\t\t\t\n\t\t\tstrSQL.append(\"INSERT INTO \");\n\t\t\tstrSQL.append(TableInfo.get(entity.getClass()).getTableName());\n\t\t\tstrSQL.append(\" (\");\n\t\t\tfor(KeyValue kv : keyValueList){\n\t\t\t\tstrSQL.append(kv.getKey()).append(\",\");\n\t\t\t\tsqlInfo.addValue(kv.getValue());\n\t\t\t}\n\t\t\tstrSQL.deleteCharAt(strSQL.length() - 1);\n\t\t\tstrSQL.append(\") VALUES ( \");\n\t\t\t\n\t\t\tint length = keyValueList.size();\n\t\t\tfor(int i =0 ; i < length;i++){\n\t\t\t\tstrSQL.append(\"?,\");\n\t\t\t}\n\t\t\tstrSQL.deleteCharAt(strSQL.length() - 1);\n\t\t\tstrSQL.append(\")\");\n\t\t\t\n\t\t\tsqlInfo.setSql(strSQL.toString());\n\t\t}\n\t\t\n\t\treturn sqlInfo;\n\t}\n\t\n\tpublic static List<KeyValue> getSaveKeyValueListByEntity(Object entity){\n\t\t\n\t\tList<KeyValue> keyValueList = new ArrayList<KeyValue>();\n\t\t\n\t\tTableInfo table = TableInfo.get(entity.getClass());\n\t\tObject idvalue = table.getId().getValue(entity);\n\t\t\n\t\tif(!(idvalue instanceof Integer)){ //用了非自增长,添加id , 采用自增长就不需要添加id了\n\t\t\tif(idvalue instanceof String && idvalue != null){\n\t\t\t\tKeyValue kv = new KeyValue(table.getId().getColumn(),idvalue);\n\t\t\t\tkeyValueList.add(kv);\n\t\t\t}\n\t\t}\n\t\t\n\t\t//添加属性\n\t\tCollection<Property> propertys = table.propertyMap.values();\n\t\tfor(Property property : propertys){\n\t\t\tKeyValue kv = property2KeyValue(property,entity) ;\n\t\t\tif(kv!=null)\n\t\t\t\tkeyValueList.add(kv);\n\t\t}\n\t\t\n\t\t//添加外键（多对一）\n\t\tCollection<ManyToOne> manyToOnes = table.manyToOneMap.values();\n\t\tfor(ManyToOne many:manyToOnes){\n\t\t\tKeyValue kv = manyToOne2KeyValue(many,entity);\n\t\t\tif(kv!=null) keyValueList.add(kv);\n\t\t}\n\t\t\n\t\treturn keyValueList;\n\t}\n\t\n\t\n\tprivate static String getDeleteSqlBytableName(String tableName){\n\t\treturn \"DELETE FROM \"+ tableName;\n\t}\n\t\n\t\n\tpublic static SqlInfo buildDeleteSql(Object entity){\n\t\tTableInfo table=TableInfo.get(entity.getClass());\n\t\t\n\t\tId id = table.getId();\n\t\tObject idvalue = id.getValue(entity);\n\t\t\n\t\tif(idvalue == null ){\n\t\t\tthrow new DbException(\"getDeleteSQL:\"+entity.getClass()+\" id value is null\");\n\t\t}\n\t\tStringBuffer strSQL = new StringBuffer(getDeleteSqlBytableName(table.getTableName()));\n\t\tstrSQL.append(\" WHERE \").append(id.getColumn()).append(\"=?\");\n\t\t\n\t\tSqlInfo sqlInfo = new SqlInfo();\n\t\tsqlInfo.setSql(strSQL.toString());\n\t\tsqlInfo.addValue(idvalue);\n\t\t\n\t\treturn sqlInfo;\n\t}\n\t\n\t\n\t\n\tpublic static SqlInfo buildDeleteSql(Class<?> clazz , Object idValue){\n\t\tTableInfo table=TableInfo.get(clazz);\n\t\tId id=table.getId();\n\t\t\n\t\tif(null == idValue) {\n\t\t\tthrow new DbException(\"getDeleteSQL:idValue is null\");\n\t\t}\n\t\t\n\t\tStringBuffer strSQL = new StringBuffer(getDeleteSqlBytableName(table.getTableName()));\n\t\tstrSQL.append(\" WHERE \").append(id.getColumn()).append(\"=?\");\n\t\t\n\t\tSqlInfo sqlInfo = new SqlInfo();\n\t\tsqlInfo.setSql(strSQL.toString());\n\t\tsqlInfo.addValue(idValue);\n\t\t\n\t\treturn sqlInfo;\n\t}\n\t\n\t/**\n\t * 根据条件删除数据 ，条件为空的时候将会删除所有的数据\n\t * @param clazz\n\t * @param strWhere\n\t * @return\n\t */\n\tpublic static String buildDeleteSql(Class<?> clazz , String strWhere){\n\t\tTableInfo table=TableInfo.get(clazz);\n\t\tStringBuffer strSQL = new StringBuffer(getDeleteSqlBytableName(table.getTableName()));\n\t\t\n\t\tif(!TextUtils.isEmpty(strWhere)){\n\t\t\tstrSQL.append(\" WHERE \");\n\t\t\tstrSQL.append(strWhere);\n\t\t}\n\t\t\n\t\treturn strSQL.toString();\n\t}\n\n\n\t////////////////////////////select sql start///////////////////////////////////////\n\t\n\n\tprivate static String getSelectSqlByTableName(String tableName){\n\t\treturn new StringBuffer(\"SELECT * FROM \").append(tableName).toString();\n\t}\n\n\n\tpublic static String getSelectSQL(Class<?> clazz,Object idValue){\n\t\tTableInfo table=TableInfo.get(clazz);\n\t\t\n\t\tStringBuffer strSQL = new StringBuffer(getSelectSqlByTableName(table.getTableName()));\n\t\tstrSQL.append(\" WHERE \");\n\t\tstrSQL.append(getPropertyStrSql(table.getId().getColumn(), idValue));\n\t\t\n\t\treturn strSQL.toString();\n\t}\n\t\n\tpublic static SqlInfo getSelectSqlAsSqlInfo(Class<?> clazz,Object idValue){\n\t\tTableInfo table=TableInfo.get(clazz);\n\t\t\n\t\tStringBuffer strSQL = new StringBuffer(getSelectSqlByTableName(table.getTableName()));\n\t\tstrSQL.append(\" WHERE \").append(table.getId().getColumn()).append(\"=?\");\n\t\t\n\t\tSqlInfo sqlInfo = new SqlInfo();\n\t\tsqlInfo.setSql(strSQL.toString());\n\t\tsqlInfo.addValue(idValue);\n\t\t\n\t\treturn sqlInfo;\n\t}\n\t\n\t\n\tpublic static String getSelectSQL(Class<?> clazz){\n\t\treturn getSelectSqlByTableName(TableInfo.get(clazz).getTableName());\n\t}\n\t\n\tpublic static String getSelectSQLByWhere(Class<?> clazz,String strWhere){\n\t\tTableInfo table=TableInfo.get(clazz);\n\t\t\n\t\tStringBuffer strSQL = new StringBuffer(getSelectSqlByTableName(table.getTableName()));\n\t\t\n\t\tif(!TextUtils.isEmpty(strWhere)){\n\t\t\tstrSQL.append(\" WHERE \").append(strWhere);\n\t\t}\n\t\t\n\t\treturn strSQL.toString();\n\t}\n\t\n\t//////////////////////////////update sql start/////////////////////////////////////////////\n\t\n\tpublic static SqlInfo getUpdateSqlAsSqlInfo(Object entity){\n\t\t\n\t\tTableInfo table=TableInfo.get(entity.getClass());\n\t\tObject idvalue=table.getId().getValue(entity);\n\t\t\n\t\tif(null == idvalue ) {//主键值不能为null，否则不能更新\n\t\t\tthrow new DbException(\"this entity[\"+entity.getClass()+\"]'s id value is null\");\n\t\t}\n\t\t\n\t\tList<KeyValue> keyValueList = new ArrayList<KeyValue>();\n\t\t//添加属性\n\t\tCollection<Property> propertys = table.propertyMap.values();\n\t\tfor(Property property : propertys){\n\t\t\tKeyValue kv = property2KeyValue(property,entity) ;\n\t\t\tif(kv!=null)\n\t\t\t\tkeyValueList.add(kv);\n\t\t}\n\t\t\n\t\t//添加外键（多对一）\n\t\tCollection<ManyToOne> manyToOnes = table.manyToOneMap.values();\n\t\tfor(ManyToOne many:manyToOnes){\n\t\t\tKeyValue kv = manyToOne2KeyValue(many,entity);\n\t\t\tif(kv!=null) keyValueList.add(kv);\n\t\t}\n\t\t\n\t\tif(keyValueList == null || keyValueList.size()==0) return null ;\n\t\t\n\t\tSqlInfo sqlInfo = new SqlInfo();\n\t\tStringBuffer strSQL=new StringBuffer(\"UPDATE \");\n\t\tstrSQL.append(table.getTableName());\n\t\tstrSQL.append(\" SET \");\n\t\tfor(KeyValue kv : keyValueList){\n\t\t\tstrSQL.append(kv.getKey()).append(\"=?,\");\n\t\t\tsqlInfo.addValue(kv.getValue());\n\t\t}\n\t\tstrSQL.deleteCharAt(strSQL.length() - 1);\n\t\tstrSQL.append(\" WHERE \").append(table.getId().getColumn()).append(\"=?\");\n\t\tsqlInfo.addValue(idvalue);\n\t\tsqlInfo.setSql(strSQL.toString());\n\t\treturn sqlInfo;\n\t}\n\t\n\n\t\n\t\n\tpublic static SqlInfo getUpdateSqlAsSqlInfo(Object entity,String  strWhere){\n\t\t\n\t\tTableInfo table=TableInfo.get(entity.getClass());\n\t\t\n\t\tList<KeyValue> keyValueList = new ArrayList<KeyValue>();\n\t\t\n\t\t//添加属性\n\t\tCollection<Property> propertys = table.propertyMap.values();\n\t\tfor(Property property : propertys){\n\t\t\tKeyValue kv = property2KeyValue(property,entity) ;\n\t\t\tif(kv!=null) keyValueList.add(kv);\n\t\t}\n\t\t\n\t\t//添加外键（多对一）\n\t\tCollection<ManyToOne> manyToOnes = table.manyToOneMap.values();\n\t\tfor(ManyToOne many:manyToOnes){\n\t\t\tKeyValue kv = manyToOne2KeyValue(many,entity);\n\t\t\tif(kv!=null) keyValueList.add(kv);\n\t\t}\n\t\t\n\t\tif(keyValueList == null || keyValueList.size()==0) {\n\t\t\tthrow new DbException(\"this entity[\"+entity.getClass()+\"] has no property\"); \n\t\t}\n\t\t\n\t\tSqlInfo sqlInfo = new SqlInfo();\n\t\tStringBuffer strSQL=new StringBuffer(\"UPDATE \");\n\t\tstrSQL.append(table.getTableName());\n\t\tstrSQL.append(\" SET \");\n\t\tfor(KeyValue kv : keyValueList){\n\t\t\tstrSQL.append(kv.getKey()).append(\"=?,\");\n\t\t\tsqlInfo.addValue(kv.getValue());\n\t\t}\n\t\tstrSQL.deleteCharAt(strSQL.length() - 1);\n\t\tif(!TextUtils.isEmpty(strWhere)){\n\t\t\tstrSQL.append(\" WHERE \").append(strWhere);\n\t\t}\n\t\tsqlInfo.setSql(strSQL.toString());\t\n\t\treturn sqlInfo;\n\t}\n\t\n\t\n\t\n\tpublic static String getCreatTableSQL(Class<?> clazz){\n\t\tTableInfo table=TableInfo.get(clazz);\n\t\t\n\t\tId id=table.getId();\n\t\tStringBuffer strSQL = new StringBuffer();\n\t\tstrSQL.append(\"CREATE TABLE IF NOT EXISTS \");\n\t\tstrSQL.append(table.getTableName());\n\t\tstrSQL.append(\" ( \");\n\t\t\n\t\tClass<?> primaryClazz = id.getDataType();\n\t\tif( primaryClazz == int.class || primaryClazz==Integer.class \n\t\t\t\t|| primaryClazz == long.class || primaryClazz == Long.class){\n\t\t\tstrSQL.append(id.getColumn()).append(\" INTEGER PRIMARY KEY AUTOINCREMENT,\");\n\t\t}else{\n\t\t\tstrSQL.append(id.getColumn()).append(\" TEXT PRIMARY KEY,\");\n\t\t}\n\t\t\t\n\t\t\n\t\t\n\t\tCollection<Property> propertys = table.propertyMap.values();\n\t\tfor(Property property : propertys){\n\t\t\tstrSQL.append(property.getColumn());\n\t\t\tClass<?> dataType =  property.getDataType();\n\t\t\tif( dataType== int.class || dataType == Integer.class \n\t\t\t   || dataType == long.class || dataType == Long.class){\n\t\t\t\tstrSQL.append(\" INTEGER\");\n\t\t\t}else if(dataType == float.class ||dataType == Float.class \n\t\t\t\t\t||dataType == double.class || dataType == Double.class){\n\t\t\t\tstrSQL.append(\" REAL\");\n\t\t\t}else if (dataType == boolean.class || dataType == Boolean.class) {\n\t\t\t\tstrSQL.append(\" NUMERIC\");\n\t\t\t}\n\t\t\tstrSQL.append(\",\");\n\t\t}\n\t\t\n\t\tCollection<ManyToOne> manyToOnes = table.manyToOneMap.values();\n\t\tfor(ManyToOne manyToOne : manyToOnes){\n\t\t\tstrSQL.append(manyToOne.getColumn())\n\t\t\t.append(\" INTEGER\")\n\t\t\t.append(\",\");\n\t\t}\n\t\tstrSQL.deleteCharAt(strSQL.length() - 1);\n\t\tstrSQL.append(\" )\");\n\t\treturn strSQL.toString();\n\t}\n\t\n\t\n\t/**\n\t * @param key\n\t * @param value\n\t * @return eg1: name='afinal'  eg2: id=100\n\t */\n\tprivate static String getPropertyStrSql(String key,Object value){\n\t\tStringBuffer sbSQL = new StringBuffer(key).append(\"=\");\n\t\tif(value instanceof String || value instanceof java.util.Date || value instanceof java.sql.Date){\n\t\t\tsbSQL.append(\"'\").append(value).append(\"'\");\n\t\t}else{\n\t\t\tsbSQL.append(value);\n\t\t}\n\t\treturn sbSQL.toString();\n\t}\n\t\n\t\n\t\n\tprivate static KeyValue property2KeyValue(Property property , Object entity){\n\t\tKeyValue kv = null ;\n\t\tString pcolumn=property.getColumn();\n\t\tObject value = property.getValue(entity);\n\t\tif(value!=null){\n\t\t\tkv = new KeyValue(pcolumn, value);\n\t\t}else{\n\t\t\tif(property.getDefaultValue()!=null && property.getDefaultValue().trim().length()!=0)\n\t\t\t\tkv = new KeyValue(pcolumn, property.getDefaultValue());\n\t\t}\n\t\treturn kv;\n\t}\n\t\n\t\n\tprivate static KeyValue manyToOne2KeyValue(ManyToOne many , Object entity){\n\t\tKeyValue kv = null ;\n\t\tString manycolumn=many.getColumn();\n\t\tObject manyobject=many.getValue(entity);\n\t\tif(manyobject!=null){\n\t\t\tObject manyvalue;\n            if(manyobject.getClass()==ManyToOneLazyLoader.class){\n                manyvalue = TableInfo.get(many.getManyClass()).getId().getValue(((ManyToOneLazyLoader)manyobject).get());\n            }else{\n                manyvalue = TableInfo.get(manyobject.getClass()).getId().getValue(manyobject);\n            }\n\t\t\tif(manycolumn!=null && manyvalue!=null){\n\t\t\t\tkv = new KeyValue(manycolumn, manyvalue);\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn kv;\n\t}\n\t\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/db/sqlite/SqlInfo.java",
    "content": "package net.tsz.afinal.db.sqlite;\n\nimport java.util.LinkedList;\n\npublic class SqlInfo {\n\t\n\tprivate String sql;\n\tprivate LinkedList<Object> bindArgs;\n\t\n\tpublic String getSql() {\n\t\treturn sql;\n\t}\n\tpublic void setSql(String sql) {\n\t\tthis.sql = sql;\n\t}\n\t\n\tpublic LinkedList<Object> getBindArgs() {\n\t\treturn bindArgs;\n\t}\n\tpublic void setBindArgs(LinkedList<Object> bindArgs) {\n\t\tthis.bindArgs = bindArgs;\n\t}\n\t\n\tpublic Object[] getBindArgsAsArray() {\n\t\tif(bindArgs!=null)\n\t\t\treturn bindArgs.toArray();\n\t\treturn null;\n\t}\n\t\n\tpublic String[] getBindArgsAsStringArray() {\n\t\tif(bindArgs!=null){\n\t\t\tString[] strings = new String[bindArgs.size()];\n\t\t\tfor(int i = 0;i<bindArgs.size();i++){\n\t\t\t\tstrings[i]=bindArgs.get(i).toString();\n\t\t\t}\n\t\t\treturn strings;\n\t\t}\n\t\treturn null;\n\t}\n\t\n\tpublic void addValue(Object obj){\n\t\tif(bindArgs == null)\n\t\t\tbindArgs = new LinkedList<Object>();\n\t\t\n\t\tbindArgs.add(obj);\n\t}\n\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/db/table/Id.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.db.table;\n\npublic class Id extends Property{\n\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/db/table/KeyValue.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.db.table;\n\nimport net.tsz.afinal.utils.FieldUtils;\n\npublic class KeyValue {\n\tprivate String key;\n\tprivate Object value;\n\t\n\tpublic KeyValue(String key, Object value) {\n\t\tthis.key = key;\n\t\tthis.value = value;\n\t}\n\t\n\t\n\tpublic KeyValue() {}\n\n\n\tpublic String getKey() {\n\t\treturn key;\n\t}\n\tpublic void setKey(String key) {\n\t\tthis.key = key;\n\t}\n\tpublic Object getValue() {\n\t\tif(value instanceof java.util.Date || value instanceof java.sql.Date){\n\t\t\treturn FieldUtils.SDF.format(value);\n\t\t}\n\t\treturn value;\n\t}\n\tpublic void setValue(Object value) {\n\t\tthis.value = value;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/db/table/ManyToOne.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.db.table;\n\npublic class ManyToOne extends Property{\n\n\tprivate Class<?> manyClass;\n\n\tpublic Class<?> getManyClass() {\n\t\treturn manyClass;\n\t}\n\n\tpublic void setManyClass(Class<?> manyClass) {\n\t\tthis.manyClass = manyClass;\n\t}\n\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/db/table/OneToMany.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.db.table;\n\npublic class OneToMany extends Property{\n\n\tprivate Class<?> oneClass;\n\n\tpublic Class<?> getOneClass() {\n\t\treturn oneClass;\n\t}\n\n\tpublic void setOneClass(Class<?> oneClass) {\n\t\tthis.oneClass = oneClass;\n\t}\n\n\t\n\t\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/db/table/Property.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.db.table;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.Date;\n\nimport net.tsz.afinal.utils.FieldUtils;\n\n/**\n * @title 属性\n * @description 【非主键】的【基本数据类型】 都是属性\n * @author michael Young (www.YangFuhai.com)\n * @version 1.0\n * @created 2012-10-10\n */\npublic class Property {\n\t\n\tprivate String fieldName;\n\tprivate String column;\n\tprivate String defaultValue;\n\tprivate Class<?> dataType;\n\tprivate Field field;\n\t\n\tprivate Method get;\n\tprivate Method set;\n\t\n\tpublic void setValue(Object receiver , Object value){\n\t\tif(set!=null && value!=null){\n\t\t\ttry {\n\t\t\t\tif (dataType == String.class) {\n\t\t\t\t\tset.invoke(receiver, value.toString());\n\t\t\t\t} else if (dataType == int.class || dataType == Integer.class) {\n\t\t\t\t\tset.invoke(receiver, value == null ? (Integer) null : Integer.parseInt(value.toString()));\n\t\t\t\t} else if (dataType == float.class || dataType == Float.class) {\n\t\t\t\t\tset.invoke(receiver, value == null ? (Float) null: Float.parseFloat(value.toString()));\n\t\t\t\t} else if (dataType == double.class || dataType == Double.class) {\n\t\t\t\t\tset.invoke(receiver, value == null ? (Double) null: Double.parseDouble(value.toString()));\n\t\t\t\t} else if (dataType == long.class || dataType == Long.class) {\n\t\t\t\t\tset.invoke(receiver, value == null ? (Long) null: Long.parseLong(value.toString()));\n\t\t\t\t} else if (dataType == Date.class || dataType == java.sql.Date.class) {\n\t\t\t\t\tset.invoke(receiver, value == null ? (Date) null: FieldUtils.stringToDateTime(value.toString()));\n\t\t\t\t} else if (dataType == boolean.class || dataType == Boolean.class) {\n\t\t\t\t\tset.invoke(receiver, value == null ? (Boolean) null: \"1\".equals(value.toString()));\n\t\t\t\t} else {\n\t\t\t\t\tset.invoke(receiver, value);\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}else{\n\t\t\ttry {\n\t\t\t\tfield.setAccessible(true);\n\t\t\t\tfield.set(receiver, value);\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * 获取某个实体执行某个方法的结果\n\t * @param obj\n\t * @param method\n\t * @return\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> T getValue(Object obj){\n\t\tif(obj != null && get != null) {\n\t\t\ttry {\n\t\t\t\treturn (T)get.invoke(obj);\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t\n\tpublic String getFieldName() {\n\t\treturn fieldName;\n\t}\n\tpublic void setFieldName(String fieldName) {\n\t\tthis.fieldName = fieldName;\n\t}\n\tpublic String getColumn() {\n\t\treturn column;\n\t}\n\tpublic void setColumn(String column) {\n\t\tthis.column = column;\n\t}\n\tpublic String getDefaultValue() {\n\t\treturn defaultValue;\n\t}\n\tpublic void setDefaultValue(String defaultValue) {\n\t\tthis.defaultValue = defaultValue;\n\t}\n\tpublic Class<?> getDataType() {\n\t\treturn dataType;\n\t}\n\tpublic void setDataType(Class<?> dataType) {\n\t\tthis.dataType = dataType;\n\t}\n\tpublic Method getGet() {\n\t\treturn get;\n\t}\n\tpublic void setGet(Method get) {\n\t\tthis.get = get;\n\t}\n\tpublic Method getSet() {\n\t\treturn set;\n\t}\n\tpublic void setSet(Method set) {\n\t\tthis.set = set;\n\t}\n\n\tpublic Field getField() {\n\t\treturn field;\n\t}\n\n\tpublic void setField(Field field) {\n\t\tthis.field = field;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/db/table/TableInfo.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.db.table;\n\nimport net.tsz.afinal.exception.DbException;\nimport net.tsz.afinal.utils.ClassUtils;\nimport net.tsz.afinal.utils.FieldUtils;\n\nimport java.lang.reflect.Field;\nimport java.util.HashMap;\nimport java.util.List;\n\n\npublic class TableInfo {\n\n\tprivate String className;\n\tprivate String tableName;\n\t\n\tprivate Id id;\n\t\n\tpublic final HashMap<String, Property> propertyMap = new HashMap<String, Property>();\n\tpublic final HashMap<String, OneToMany> oneToManyMap = new HashMap<String, OneToMany>();\n\tpublic final HashMap<String, ManyToOne> manyToOneMap = new HashMap<String, ManyToOne>();\n\t\n\tprivate boolean checkDatabese;//在对实体进行数据库操作的时候查询是否已经有表了，只需查询一遍，用此标示\n\t\n\t\n\tprivate static final HashMap<String, TableInfo> tableInfoMap = new HashMap<String, TableInfo>();\n\t\n\tprivate TableInfo(){}\n\t\n\t@SuppressWarnings(\"unused\")\n\tpublic static  TableInfo get(Class<?> clazz){\n\t\tif(clazz == null) \n\t\t\tthrow new DbException(\"table info get error,because the clazz is null\");\n\t\t\n\t\tTableInfo tableInfo = tableInfoMap.get(clazz.getName());\n\t\tif( tableInfo == null ){\n\t\t\ttableInfo = new TableInfo();\n\t\t\t\n\t\t\ttableInfo.setTableName(ClassUtils.getTableName(clazz));\n\t\t\ttableInfo.setClassName(clazz.getName());\n\t\t\t\n\t\t\tField idField = ClassUtils.getPrimaryKeyField(clazz);\n\t\t\tif(idField != null){\n\t\t\t\tId id = new Id();\n\t\t\t\tid.setColumn(FieldUtils.getColumnByField(idField));\n\t\t\t\tid.setFieldName(idField.getName());\n\t\t\t\tid.setSet(FieldUtils.getFieldSetMethod(clazz, idField));\n\t\t\t\tid.setGet(FieldUtils.getFieldGetMethod(clazz, idField));\n\t\t\t\tid.setDataType(idField.getType());\n\t\t\t\t\n\t\t\t\ttableInfo.setId(id);\n\t\t\t}else{\n\t\t\t\tthrow new DbException(\"the class[\"+clazz+\"]'s idField is null , \\n you can define _id,id property or use annotation @id to solution this exception\");\n\t\t\t}\n\t\t\t\n\t\t\tList<Property> pList = ClassUtils.getPropertyList(clazz);\n\t\t\tif(pList!=null){\n\t\t\t\tfor(Property p : pList){\n\t\t\t\t\tif(p!=null)\n\t\t\t\t\t\ttableInfo.propertyMap.put(p.getColumn(), p);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tList<ManyToOne> mList = ClassUtils.getManyToOneList(clazz);\n\t\t\tif(mList!=null){\n\t\t\t\tfor(ManyToOne m : mList){\n\t\t\t\t\tif(m!=null)\n\t\t\t\t\t\ttableInfo.manyToOneMap.put(m.getColumn(), m);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tList<OneToMany> oList = ClassUtils.getOneToManyList(clazz);\n\t\t\tif(oList!=null){\n\t\t\t\tfor(OneToMany o : oList){\n\t\t\t\t\tif(o!=null)\n\t\t\t\t\t\ttableInfo.oneToManyMap.put(o.getColumn(), o);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\ttableInfoMap.put(clazz.getName(), tableInfo);\n\t\t}\n\t\t\n\t\tif(tableInfo == null ) \n\t\t\tthrow new DbException(\"the class[\"+clazz+\"]'s table is null\");\n\t\t\n\t\treturn tableInfo;\n\t}\n\t\n\t\n\tpublic static TableInfo get(String className){\n\t\ttry {\n\t\t\treturn get(Class.forName(className));\n\t\t} catch (ClassNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\t\n\n\tpublic String getClassName() {\n\t\treturn className;\n\t}\n\n\tpublic void setClassName(String className) {\n\t\tthis.className = className;\n\t}\n\n\tpublic String getTableName() {\n\t\treturn tableName;\n\t}\n\n\tpublic void setTableName(String tableName) {\n\t\tthis.tableName = tableName;\n\t}\n\n\tpublic Id getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Id id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic boolean isCheckDatabese() {\n\t\treturn checkDatabese;\n\t}\n\n\tpublic void setCheckDatabese(boolean checkDatabese) {\n\t\tthis.checkDatabese = checkDatabese;\n\t}\n\n\t\n\t\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/exception/AfinalException.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.exception;\n\npublic class AfinalException extends RuntimeException {\n\tprivate static final long serialVersionUID = 1L;\n\t\n\tpublic AfinalException() {\n\t\tsuper();\n\t}\n\t\n\tpublic AfinalException(String msg) {\n\t\tsuper(msg);\n\t}\n\t\n\tpublic AfinalException(Throwable ex) {\n\t\tsuper(ex);\n\t}\n\t\n\tpublic AfinalException(String msg,Throwable ex) {\n\t\tsuper(msg,ex);\n\t}\n\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/exception/DbException.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.exception;\n\npublic class DbException extends AfinalException {\n\tprivate static final long serialVersionUID = 1L;\n\t\n\tpublic DbException() {}\n\t\n\t\n\tpublic DbException(String msg) {\n\t\tsuper(msg);\n\t}\n\t\n\tpublic DbException(Throwable ex) {\n\t\tsuper(ex);\n\t}\n\t\n\tpublic DbException(String msg,Throwable ex) {\n\t\tsuper(msg,ex);\n\t}\n\t\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/utils/ClassUtils.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.utils;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport net.tsz.afinal.annotation.sqlite.Id;\nimport net.tsz.afinal.annotation.sqlite.Table;\nimport net.tsz.afinal.db.sqlite.ManyToOneLazyLoader;\nimport net.tsz.afinal.db.table.ManyToOne;\nimport net.tsz.afinal.db.table.OneToMany;\nimport net.tsz.afinal.db.table.Property;\nimport net.tsz.afinal.exception.DbException;\n\npublic class ClassUtils {\n\t\n\t\n\t/**\n\t * 根据实体类 获得 实体类对应的表名\n\t * @param entity\n\t * @return\n\t */\n\tpublic static String getTableName(Class<?> clazz) {\n\t\tTable table = clazz.getAnnotation(Table.class);\n\t\tif(table == null || table.name().trim().length() == 0 ){\n\t\t\t//当没有注解的时候默认用类的名称作为表名,并把点（.）替换为下划线(_)\n\t\t\treturn clazz.getName().replace('.', '_');\n\t\t}\n\t\treturn table.name();\n\t}\n\t\n\tpublic static Object getPrimaryKeyValue(Object entity) {\n\t\treturn FieldUtils.getFieldValue(entity,ClassUtils.getPrimaryKeyField(entity.getClass()));\n\t}\n\t\n\t/**\n\t * 根据实体类 获得 实体类对应的表名\n\t * @param entity\n\t * @return\n\t */\n\tpublic static String getPrimaryKeyColumn(Class<?> clazz) {\n\t\tString primaryKey = null ;\n\t\tField[] fields = clazz.getDeclaredFields();\n\t\tif(fields != null){\n\t\t\tId idAnnotation = null ;\n\t\t\tField idField = null ;\n\t\t\t\n\t\t\tfor(Field field : fields){ //获取ID注解\n\t\t\t\tidAnnotation = field.getAnnotation(Id.class);\n\t\t\t\tif(idAnnotation != null){\n\t\t\t\t\tidField = field;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif(idAnnotation != null){ //有ID注解\n\t\t\t\tprimaryKey = idAnnotation.column();\n\t\t\t\tif(primaryKey == null || primaryKey.trim().length() == 0)\n\t\t\t\t\tprimaryKey = idField.getName();\n\t\t\t}else{ //没有ID注解,默认去找 _id 和 id 为主键，优先寻找 _id\n\t\t\t\tfor(Field field : fields){\n\t\t\t\t\tif(\"_id\".equals(field.getName()))\n\t\t\t\t\t\treturn \"_id\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor(Field field : fields){\n\t\t\t\t\tif(\"id\".equals(field.getName()))\n\t\t\t\t\t\treturn \"id\";\n\t\t\t\t}\n\t\t\t}\n\t\t}else{\n\t\t\tthrow new RuntimeException(\"this model[\"+clazz+\"] has no field\");\n\t\t}\n\t\treturn primaryKey;\n\t}\n\t\n\t\n\t/**\n\t * 根据实体类 获得 实体类对应的表名\n\t * @param entity\n\t * @return\n\t */\n\tpublic static Field getPrimaryKeyField(Class<?> clazz) {\n\t\tField primaryKeyField = null ;\n\t\tField[] fields = clazz.getDeclaredFields();\n\t\tif(fields != null){\n\t\t\t\n\t\t\tfor(Field field : fields){ //获取ID注解\n\t\t\t\tif(field.getAnnotation(Id.class) != null){\n\t\t\t\t\tprimaryKeyField = field;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif(primaryKeyField == null){ //没有ID注解\n\t\t\t\tfor(Field field : fields){\n\t\t\t\t\tif(\"_id\".equals(field.getName())){\n\t\t\t\t\t\tprimaryKeyField = field;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif(primaryKeyField == null){ // 如果没有_id的字段\n\t\t\t\tfor(Field field : fields){\n\t\t\t\t\tif(\"id\".equals(field.getName())){\n\t\t\t\t\t\tprimaryKeyField = field;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t}else{\n\t\t\tthrow new RuntimeException(\"this model[\"+clazz+\"] has no field\");\n\t\t}\n\t\treturn primaryKeyField;\n\t}\n\t\n\t\n\t/**\n\t * 根据实体类 获得 实体类对应的表名\n\t * @param entity\n\t * @return\n\t */\n\tpublic static String getPrimaryKeyFieldName(Class<?> clazz) {\n\t\tField f = getPrimaryKeyField(clazz);\n\t\treturn f==null ? null:f.getName();\n\t}\n\t\n\t\n\t\n\t/**\n\t * 将对象转换为ContentValues\n\t * \n\t * @param entity\n\t * @param selective 是否忽略 值为null的字段\n\t * @return\n\t */\n\tpublic static List<Property> getPropertyList(Class<?> clazz) {\n\t\t\n\t\tList<Property> plist = new ArrayList<Property>();\n\t\ttry {\n\t\t\tField[] fs = clazz.getDeclaredFields();\n\t\t\tString primaryKeyFieldName = getPrimaryKeyFieldName(clazz);\n\t\t\tfor (Field f : fs) {\n\t\t\t\t//必须是基本数据类型和没有标瞬时态的字段\n\t\t\t\tif(!FieldUtils.isTransient(f)){\n\t\t\t\t\tif (FieldUtils.isBaseDateType(f)) {\n\t\t\t\t\t\t\n\t\t\t\t\t\tif(f.getName().equals(primaryKeyFieldName)) //过滤主键\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\n\t\t\t\t\t\tProperty property = new Property();\n\t\t\t\t\t\n\t\t\t\t\t\tproperty.setColumn(FieldUtils.getColumnByField(f));\n\t\t\t\t\t\tproperty.setFieldName(f.getName());\n\t\t\t\t\t\tproperty.setDataType(f.getType());\n\t\t\t\t\t\tproperty.setDefaultValue(FieldUtils.getPropertyDefaultValue(f));\n\t\t\t\t\t\tproperty.setSet(FieldUtils.getFieldSetMethod(clazz, f));\n\t\t\t\t\t\tproperty.setGet(FieldUtils.getFieldGetMethod(clazz, f));\n\t\t\t\t\t\tproperty.setField(f);\n\t\t\t\t\t\t\n\t\t\t\t\t\tplist.add(property);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn plist;\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e.getMessage(), e);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * 将对象转换为ContentValues\n\t * \n\t * @param entity\n\t * @param selective 是否忽略 值为null的字段\n\t * @return\n\t */\n\tpublic static List<ManyToOne> getManyToOneList(Class<?> clazz) {\n\t\t\n\t\tList<ManyToOne> mList = new ArrayList<ManyToOne>();\n\t\ttry {\n\t\t\tField[] fs = clazz.getDeclaredFields();\n\t\t\tfor (Field f : fs) {\n\t\t\t\tif (!FieldUtils.isTransient(f) && FieldUtils.isManyToOne(f)) {\n\t\t\t\t\t\n\t\t\t\t\tManyToOne mto = new ManyToOne();\n                    //如果类型为ManyToOneLazyLoader则取第二个参数作为manyClass（一方实体） 2013-7-26\n                    if(f.getType()==ManyToOneLazyLoader.class){\n                        Class<?> pClazz = (Class<?>)((ParameterizedType)f.getGenericType()).getActualTypeArguments()[1];\n                        if(pClazz!=null)\n                            mto.setManyClass(pClazz);\n                    }else {\n\t\t\t\t\t    mto.setManyClass(f.getType());\n                    }\n\t\t\t\t\tmto.setColumn(FieldUtils.getColumnByField(f));\n\t\t\t\t\tmto.setFieldName(f.getName());\n\t\t\t\t\tmto.setDataType(f.getType());\t\n\t\t\t\t\tmto.setSet(FieldUtils.getFieldSetMethod(clazz, f));\n\t\t\t\t\tmto.setGet(FieldUtils.getFieldGetMethod(clazz, f));\n\t\t\t\t\t\n\t\t\t\t\tmList.add(mto);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn mList;\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e.getMessage(), e);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * 将对象转换为ContentValues\n\t * \n\t * @param entity\n\t * @param selective 是否忽略 值为null的字段\n\t * @return\n\t */\n\tpublic static List<OneToMany> getOneToManyList(Class<?> clazz) {\n\t\t\n\t\tList<OneToMany> oList = new ArrayList<OneToMany>();\n\t\ttry {\n\t\t\tField[] fs = clazz.getDeclaredFields();\n\t\t\tfor (Field f : fs) {\n\t\t\t\tif (!FieldUtils.isTransient(f) && FieldUtils.isOneToMany(f)) {\n\t\t\t\t\t\n\t\t\t\t\tOneToMany otm = new OneToMany();\n\t\t\t\t\t\n\t\t\t\t\totm.setColumn(FieldUtils.getColumnByField(f));\n\t\t\t\t\totm.setFieldName(f.getName());\n\t\t\t\t\t\n\t\t\t\t\tType type = f.getGenericType();\n\t\t\t\t\t\n\t\t\t\t\tif(type instanceof ParameterizedType){\n\t\t\t\t\t\tParameterizedType pType = (ParameterizedType) f.getGenericType();\n                        //如果类型参数为2则认为是LazyLoader 2013-7-25\n                        if(pType.getActualTypeArguments().length==1){\n\t\t\t\t\t\t    Class<?> pClazz = (Class<?>)pType.getActualTypeArguments()[0];\n\t\t\t\t\t\t    if(pClazz!=null)\n\t\t\t\t\t\t\t    otm.setOneClass(pClazz);\n                        }else{\n                            Class<?> pClazz = (Class<?>)pType.getActualTypeArguments()[1];\n                            if(pClazz!=null)\n                                otm.setOneClass(pClazz);\n                        }\n\t\t\t\t\t}else{\n\t\t\t\t\t\tthrow new DbException(\"getOneToManyList Exception:\"+f.getName()+\"'s type is null\");\n\t\t\t\t\t}\n\t\t\t\t\t/*修正类型赋值错误的bug，f.getClass返回的是Filed*/\n\t\t\t\t\totm.setDataType(f.getType());\n\t\t\t\t\totm.setSet(FieldUtils.getFieldSetMethod(clazz, f));\n\t\t\t\t\totm.setGet(FieldUtils.getFieldGetMethod(clazz, f));\n\t\t\t\t\t\n\t\t\t\t\toList.add(otm);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn oList;\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e.getMessage(), e);\n\t\t}\n\t}\t\n\t\n\t\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/utils/FieldUtils.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.utils;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport net.tsz.afinal.annotation.sqlite.Id;\nimport net.tsz.afinal.annotation.sqlite.ManyToOne;\nimport net.tsz.afinal.annotation.sqlite.OneToMany;\nimport net.tsz.afinal.annotation.sqlite.Property;\nimport net.tsz.afinal.annotation.sqlite.Transient;\n\n/**\n * @title 字段操作工具类\n * @description 描述\n * @company 探索者网络工作室(www.tsz.net)\n * @author michael Young (www.YangFuhai.com)\n * @version 1.0\n * @created 2012-10-10\n */\npublic class FieldUtils {\n\tpublic static final SimpleDateFormat SDF = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\t\n\tpublic static Method getFieldGetMethod(Class<?> clazz, Field f) {\n\t\tString fn = f.getName();\n\t\tMethod m = null;\n\t\tif(f.getType() == boolean.class){\n\t\t\tm = getBooleanFieldGetMethod(clazz, fn);\n\t\t}\n\t\tif(m == null ){\n\t\t\tm = getFieldGetMethod(clazz, fn);\n\t\t}\n\t\treturn m;\n\t}\n\t\n\tpublic static Method getBooleanFieldGetMethod(Class<?> clazz, String fieldName) {\n\t\tString mn = \"is\" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);\n\t\tif(isISStart(fieldName)){\n\t\t\tmn = fieldName;\n\t\t}\n\t\ttry {\n\t\t\treturn clazz.getDeclaredMethod(mn);\n\t\t} catch (NoSuchMethodException e) {\n\t\t\te.printStackTrace();\n\t\t\treturn null;\n\t\t}\n\t}\n\t\n\t\n\tpublic static Method getBooleanFieldSetMethod(Class<?> clazz, Field f) {\n\t\tString fn = f.getName();\n\t\tString mn = \"set\" + fn.substring(0, 1).toUpperCase() + fn.substring(1);\n\t\tif(isISStart(f.getName())){\n\t\t\tmn = \"set\" + fn.substring(2, 3).toUpperCase() + fn.substring(3);\n\t\t}\n\t\ttry {\n\t\t\treturn clazz.getDeclaredMethod(mn, f.getType());\n\t\t} catch (NoSuchMethodException e) {\n\t\t\te.printStackTrace();\n\t\t\treturn null;\n\t\t}\n\t}\n\t\n\t\n\tprivate static boolean isISStart(String fieldName){\n\t\tif(fieldName==null || fieldName.trim().length()==0)\n\t\t\treturn false;\n\t\t//is开头，并且is之后第一个字母是大写 比如 isAdmin\n\t\treturn fieldName.startsWith(\"is\") && !Character.isLowerCase(fieldName.charAt(2));\n\t}\n\t\n\t\n\t\n\t\n\tpublic static Method getFieldGetMethod(Class<?> clazz, String fieldName) {\n\t\tString mn = \"get\" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);\n\t\ttry {\n\t\t\treturn clazz.getDeclaredMethod(mn);\n\t\t} catch (NoSuchMethodException e) {\n\t\t\te.printStackTrace();\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tpublic static Method getFieldSetMethod(Class<?> clazz, Field f) {\n\t\tString fn = f.getName();\n\t\tString mn = \"set\" + fn.substring(0, 1).toUpperCase() + fn.substring(1);\n\t\ttry {\n\t\t\treturn clazz.getDeclaredMethod(mn, f.getType());\n\t\t} catch (NoSuchMethodException e) {\n\t\t\tif(f.getType() == boolean.class){\n\t\t\t\treturn getBooleanFieldSetMethod(clazz, f);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\t\n\tpublic static Method getFieldSetMethod(Class<?> clazz, String fieldName) {\n\t\ttry {\n\t\t\treturn getFieldSetMethod(clazz, clazz.getDeclaredField(fieldName));\n\t\t} catch (SecurityException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (NoSuchFieldException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * 获取某个字段的值\n\t * @param entity\n\t * @param fieldName\n\t * @return\n\t */\n\tpublic static Object getFieldValue(Object entity,Field field){\n\t\tMethod method = getFieldGetMethod(entity.getClass(), field);\n\t\treturn invoke(entity, method);\n\t}\n\t\n\t/**\n\t * 获取某个字段的值\n\t * @param entity\n\t * @param fieldName\n\t * @return\n\t */\n\tpublic static Object getFieldValue(Object entity,String fieldName){\n\t\tMethod method = getFieldGetMethod(entity.getClass(), fieldName);\n\t\treturn invoke(entity, method);\n\t}\n\t\n\t/**\n\t * 设置某个字段的值\n\t * @param entity\n\t * @param fieldName\n\t * @return\n\t */\n\tpublic static void setFieldValue(Object entity,Field field,Object value){\n\t\ttry {\n\t\t\tMethod set = getFieldSetMethod(entity.getClass(), field);\n\t\t\tif (set != null) {\n\t\t\t\tset.setAccessible(true);\n\t\t\t\tClass<?> type = field.getType();\n\t\t\t\tif (type == String.class) {\n\t\t\t\t\tset.invoke(entity, value.toString());\n\t\t\t\t} else if (type == int.class || type == Integer.class) {\n\t\t\t\t\tset.invoke(entity, value == null ? (Integer) null : Integer.parseInt(value.toString()));\n\t\t\t\t} else if (type == float.class || type == Float.class) {\n\t\t\t\t\tset.invoke(entity, value == null ? (Float) null: Float.parseFloat(value.toString()));\n\t\t\t\t} else if (type == long.class || type == Long.class) {\n\t\t\t\t\tset.invoke(entity, value == null ? (Long) null: Long.parseLong(value.toString()));\n\t\t\t\t} else if (type == Date.class) {\n\t\t\t\t\tset.invoke(entity, value == null ? (Date) null: stringToDateTime(value.toString()));\n\t\t\t\t} else {\n\t\t\t\t\tset.invoke(entity, value);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * 获取某个字段的值\n\t * @param entity\n\t * @param fieldName\n\t * @return\n\t */\n\tpublic static Field getFieldByColumnName(Class<?> clazz,String columnName){\n\t\tField field = null;\n\t\tif(columnName!=null){\n\t\t\tField[] fields = clazz.getDeclaredFields();\n\t\t\tif(fields!=null && fields.length>0){\n\t\t\t\tif(columnName.equals(ClassUtils.getPrimaryKeyColumn(clazz)))\n\t\t\t\t\tfield = ClassUtils.getPrimaryKeyField(clazz);\n\t\t\t\t\t\n\t\t\t\tif(field == null){\n\t\t\t\t\tfor(Field f : fields){\n\t\t\t\t\t\tProperty property = f.getAnnotation(Property.class);\n\t\t\t\t\t\tif(property!=null && columnName.equals(property.column())){\n\t\t\t\t\t\t\tfield = f;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tManyToOne manyToOne = f.getAnnotation(ManyToOne.class);\n\t\t\t\t\t\tif(manyToOne!=null && manyToOne.column().trim().length()!=0){\n\t\t\t\t\t\t\tfield = f;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif(field == null){\n\t\t\t\t\tfield = getFieldByName(clazz, columnName);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn field;\n\t}\n\t\n\t\n\t/**\n\t * 获取某个字段的值\n\t * @param entity\n\t * @param fieldName\n\t * @return\n\t */\n\tpublic static Field getFieldByName(Class<?> clazz,String fieldName){\n\t\tField field = null;\n\t\tif(fieldName!=null){\n\t\t\ttry {\n\t\t\t\tfield = clazz.getDeclaredField(fieldName);\n\t\t\t} catch (SecurityException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t} catch (NoSuchFieldException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn field;\n\t}\n\t\n\t\n\t\n\t/**\n\t * 获取某个属性对应的 表的列\n\t * @param entity\n\t * @param fieldName\n\t * @return\n\t */\n\tpublic static String getColumnByField(Field field){\n\t\tProperty property = field.getAnnotation(Property.class);\n\t\tif(property != null && property.column().trim().length() != 0){\n\t\t\treturn property.column();\n\t\t}\n\t\t\n\t\tManyToOne manyToOne = field.getAnnotation(ManyToOne.class);\n\t\tif(manyToOne!=null && manyToOne.column().trim().length()!=0){\n\t\t\treturn manyToOne.column();\n\t\t}\n\t\t\n\t\tOneToMany oneToMany = field.getAnnotation(OneToMany.class);\n\t\tif(oneToMany!=null && oneToMany.manyColumn()!=null &&oneToMany.manyColumn().trim().length()!=0){\n\t\t\treturn oneToMany.manyColumn();\n\t\t}\n\n\t\tId id = field.getAnnotation(Id.class);\n\t\tif(id!=null && id.column().trim().length()!=0)\n\t\t\treturn id.column();\n\t\t\n\t\treturn field.getName();\n\t}\n\t\n\t\n\t\n\tpublic static String getPropertyDefaultValue(Field field){\n\t\tProperty property = field.getAnnotation(Property.class);\n\t\tif(property != null && property.defaultValue().trim().length() != 0){\n\t\t\treturn property.defaultValue();\n\t\t}\n\t\treturn null ;\n\t}\n\n\n\n\t/**\n\t * 检测 字段是否已经被标注为 非数据库字段\n\t * @param f\n\t * @return\n\t */\n\tpublic static boolean isTransient(Field f) {\n\t\treturn f.getAnnotation(Transient.class) != null;\n\t}\n\t\n\t/**\n\t * 获取某个实体执行某个方法的结果\n\t * @param obj\n\t * @param method\n\t * @return\n\t */\n\tprivate static Object invoke(Object obj , Method method){\n\t\tif(obj == null || method == null) return null;\n\t\ttry {\n\t\t\treturn method.invoke(obj);\n\t\t} catch (IllegalArgumentException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IllegalAccessException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (InvocationTargetException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t\n\tpublic static boolean isManyToOne(Field field){\n\t\treturn field.getAnnotation(ManyToOne.class)!=null;\n\t}\n\t\n\tpublic static boolean isOneToMany(Field field){\n\t\treturn field.getAnnotation(OneToMany.class)!=null;\n\t}\n\t\n\tpublic static boolean isManyToOneOrOneToMany(Field field){\n\t\treturn isManyToOne(field) || isOneToMany(field);\n\t}\n\t\n\tpublic static boolean isBaseDateType(Field field){\n\t\tClass<?> clazz = field.getType();\n\t\treturn   clazz.equals(String.class) ||  \n\t\t         clazz.equals(Integer.class)||  \n\t\t         clazz.equals(Byte.class) ||  \n\t\t         clazz.equals(Long.class) ||  \n\t\t         clazz.equals(Double.class) ||  \n\t\t         clazz.equals(Float.class) ||  \n\t\t         clazz.equals(Character.class) ||  \n\t\t         clazz.equals(Short.class) ||  \n\t\t         clazz.equals(Boolean.class) ||  \n\t\t         clazz.equals(Date.class) ||  \n\t\t         clazz.equals(Date.class) ||\n\t\t         clazz.equals(java.sql.Date.class) ||\n\t\t         clazz.isPrimitive();\n\t}\n\t\n\tpublic static Date stringToDateTime(String strDate) {\n\t\tif (strDate != null) {\n\t\t\ttry {\n\t\t\t\treturn SDF.parse(strDate);\n\t\t\t} catch (ParseException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "orm-library/src/main/java/net/tsz/afinal/utils/Utils.java",
    "content": "/**\n * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com).\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 net.tsz.afinal.utils;\n\nimport java.io.File;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.os.Environment;\nimport android.os.StatFs;\nimport android.util.Log;\n\npublic class Utils {\n\t\n\tprivate static final String TAG = \"BitmapCommonUtils\";\n\tprivate static final long POLY64REV = 0x95AC9329AC4BC9B5L;\n    private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL;\n\n    private static long[] sCrcTable = new long[256];\n\t/**\n\t * 获取可以使用的缓存目录\n\t * @param context\n\t * @param uniqueName 目录名称\n\t * @return\n\t */\n    public static File getDiskCacheDir(Context context, String uniqueName) {\n        final String cachePath = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ? \n                \t\tgetExternalCacheDir(context).getPath() : context.getCacheDir().getPath();\n\n        return new File(cachePath + File.separator + uniqueName);\n    }\n\n  \n\n    /**\n     * 获取bitmap的字节大小\n     * @param bitmap\n     * @return\n     */\n    public static int getBitmapSize(Bitmap bitmap) {\n        return bitmap.getRowBytes() * bitmap.getHeight();\n    }\n\n\n   /**\n    * 获取程序外部的缓存目录\n    * @param context\n    * @return\n    */\n    public static File getExternalCacheDir(Context context) {\n        final String cacheDir = \"/Android/data/\" + context.getPackageName() + \"/cache/\";\n        return new File(Environment.getExternalStorageDirectory().getPath() + cacheDir);\n    }\n\n    /**\n     * 获取文件路径空间大小\n     * @param path\n     * @return\n     */\n    public static long getUsableSpace(File path) {\n    \ttry{\n    \t\t final StatFs stats = new StatFs(path.getPath());\n    \t     return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks();\n    \t}catch (Exception e) {\n\t\t\tLog.e(TAG, \"获取 sdcard 缓存大小 出错，请查看AndroidManifest.xml 是否添加了sdcard的访问权限\");\n\t\t\te.printStackTrace();\n\t\t\treturn -1;\n\t\t}\n       \n    }\n    \n    \n    public static byte[] getBytes(String in) {\n        byte[] result = new byte[in.length() * 2];\n        int output = 0;\n        for (char ch : in.toCharArray()) {\n            result[output++] = (byte) (ch & 0xFF);\n            result[output++] = (byte) (ch >> 8);\n        }\n        return result;\n    }\n\n    public static boolean isSameKey(byte[] key, byte[] buffer) {\n        int n = key.length;\n        if (buffer.length < n) {\n            return false;\n        }\n        for (int i = 0; i < n; ++i) {\n            if (key[i] != buffer[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n    \n    public static byte[] copyOfRange(byte[] original, int from, int to) {\n        int newLength = to - from;\n        if (newLength < 0)\n            throw new IllegalArgumentException(from + \" > \" + to);\n        byte[] copy = new byte[newLength];\n        System.arraycopy(original, from, copy, 0,Math.min(original.length - from, newLength));\n        return copy;\n    }\n    \n    \n    \n    static {\n        //参考 http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c\n        long part;\n        for (int i = 0; i < 256; i++) {\n            part = i;\n            for (int j = 0; j < 8; j++) {\n                long x = ((int) part & 1) != 0 ? POLY64REV : 0;\n                part = (part >> 1) ^ x;\n            }\n            sCrcTable[i] = part;\n        }\n    }\n    \n    public static byte[] makeKey(String httpUrl) {\n        return getBytes(httpUrl);\n    }\n\n    /**\n     * A function thats returns a 64-bit crc for string\n     *\n     * @param in input string\n     * @return a 64-bit crc value\n     */\n    public static final long crc64Long(String in) {\n        if (in == null || in.length() == 0) {\n            return 0;\n        }\n        return crc64Long(getBytes(in));\n    }\n\n    public static final long crc64Long(byte[] buffer) {\n        long crc = INITIALCRC;\n        for (int k = 0, n = buffer.length; k < n; ++k) {\n            crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8);\n        }\n        return crc;\n    }\n\n}\n"
  },
  {
    "path": "orm-library/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">library</string>\n</resources>\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':orm-library', ':MaterialPreference'\n"
  }
]