public interface GithubDataSource {

    void setPinned(boolean active, long id);

    void logout();

    void getRepositories(GetRepositoriesCallback callback);

    void getRepositoryReferrers(Repository repository, GetRepositoryReferrersCallback callback);

    void getRepositoryClones(Repository repository, String period, GetRepositoryClonesCallback callback);

    void getRepositoryViews(Repository repository, String period, GetRepositoryViewsCallback callback);

    void getRepositoriesWithAdditionalInfo(GetRepositoriesCallback callback, boolean useCache);

    void getRepositoriesWithAdditionalInfo(long repositoryId, GetRepositoriesCallback callback, boolean useCache);

    void requestTokenFromCode(String code, RequestTokenFromCodeCallback callback);

    void getTrendingRepositories(String period, String language, GetTrendingRepositories callback,
                                 boolean useCache);

    void saveToken(String token, String tokenType);

    String getToken();

    String getTokenType();

    void getUser(GerUserCallback callback);

    @GithubLocalDataSource.TrendingLanguage
    String getDefaultLanguageForTrending();

    void setDefaultLanguageForTrending(@GithubLocalDataSource.TrendingLanguage String language);

    @GithubLocalDataSource.TrendingPeriod
    String getDefaultPeriodForTrending();

    void setDefaultPeriodForTrending(@GithubLocalDataSource.TrendingPeriod String period);

    void getStargazers(Repository repository, GetStargazersCallback callback);

    interface RequestTokenFromCodeCallback {

        void onTokenLoaded(String token, String tokenType);

        void onDataNotAvailable();
    }

    interface GetRepositoriesCallback {

        void onRepositoriesLoaded(List<Repository> repositoryList);

        void onDataNotAvailable();
    }

    interface GetRepositoryReferrersCallback {

        void onRepositoryReferrersLoaded(List<ReferringSite> referringSiteList);

        void onDataNotAvailable();
    }

    interface GetRepositoryClonesCallback {

        void onRepositoryClonesLoaded(Clones clones);

        void onDataNotAvailable();
    }

    interface GetRepositoryViewsCallback {

        void onRepositoryViewsLoaded(Views views);

        void onDataNotAvailable();
    }

    interface GetTrendingRepositories {

        void onTrendingRepositoriesLoaded(List<TrendingRepository> trendingRepositoryList,
                                          String language, String period);

        void onDataNotAvailable();
    }

    interface GerUserCallback {
        void onUserLoaded(User user);

        void onDataNotAvailable();
    }

    interface GetStargazersCallback {
        void onStargazersLoaded(List<Star> starList);

        void onDataNotAvailable();
    }
} public class GithubLocalDataSource implements GithubDataSource {

    private static final String PREFERENCES_TOKEN = "PREFERENCES_TOKEN";
    private static final String PREFERENCES_TOKEN_TYPE = "PREFERENCES_TOKEN_TYPE";
    private static final String PREFERENCES_TRENDING_PERIOD = "PREFERENCES_TRENDING_PERIOD";
    private static final String PREFERENCES_TRENDING_LANGUAGE = "PREFERENCES_TRENDING_LANGUAGE";
    public static String LOG_TAG = GithubLocalDataSource.class.getSimpleName();
    private static GithubLocalDataSource INSTANCE;
    @SuppressWarnings("all")
    private ContentResolver mContentResolver;
    private SharedPreferences mPreferences;

    private GithubLocalDataSource(@NonNull ContentResolver contentResolver,
                                  SharedPreferences preferences) {
        mContentResolver = contentResolver;
        mPreferences = preferences;
    }

    public static GithubLocalDataSource getInstance(ContentResolver contentResolver,
                                                    SharedPreferences preferences) {
        if (INSTANCE == null) {
            INSTANCE = new GithubLocalDataSource(contentResolver, preferences);
        }
        return INSTANCE;
    }

    @Override
    public void logout() {
        mContentResolver.delete(RepositoryContract.RepositoryEntry.CONTENT_URI, null, null);
        mPreferences.edit().clear().apply();
    }

    @Override
    public void getRepositories(GetRepositoriesCallback callback) {
        // Not used
        throw new IllegalStateException();
    }

    @Override
    public void getRepositoryReferrers(Repository repository, GetRepositoryReferrersCallback callback) {
        // Not used
        throw new IllegalStateException();
    }

    @Override
    public void requestTokenFromCode(String code, RequestTokenFromCodeCallback callback) {
        // Not used
        throw new IllegalStateException();
    }

    @Override
    public void getRepositoryClones(Repository repository, String period, GetRepositoryClonesCallback callback) {
        // Not used
        throw new IllegalStateException();
    }

    @Override
    public void getRepositoryViews(Repository repository, String period, GetRepositoryViewsCallback callback) {
        // Not used
        throw new IllegalStateException();
    }

    @Override
    public void getStargazers(Repository repository, GetStargazersCallback callback) {
        // Not used
        throw new IllegalStateException();
    }

    @Override
    public void getRepositoriesWithAdditionalInfo(GetRepositoriesCallback callback, boolean useCache) {
        // Not used
        throw new IllegalStateException();
    }

    @Override
    public void getRepositoriesWithAdditionalInfo(long repositoryId, GetRepositoriesCallback callback,
                                                  boolean useCache) {
        // Not used
        throw new IllegalStateException();
    }

    @Override
    public void getTrendingRepositories(String period, String language, GetTrendingRepositories callback,
                                        boolean useCache) {
        // Not used
        throw new IllegalStateException();
    }

    @Override
    public void getUser(GerUserCallback callback) {
        // Not used
        throw new IllegalStateException();
    }

    @Override
    public void saveToken(String token, String tokenType) {
        SharedPreferences.Editor editor = mPreferences.edit();
        editor.putString(PREFERENCES_TOKEN, token);
        editor.putString(PREFERENCES_TOKEN_TYPE, tokenType);
        editor.apply();
    }

    @Override
    public String getToken() {
        return mPreferences.getString(PREFERENCES_TOKEN, null);
    }

    @Override
    public String getTokenType() {
        return mPreferences.getString(PREFERENCES_TOKEN_TYPE, null);
    }

    @Override
    public
    @TrendingLanguage
    String getDefaultLanguageForTrending() {
        String language = mPreferences.getString(PREFERENCES_TRENDING_LANGUAGE,
                TrendingLanguage.JAVA);
        switch (language) {
            case TrendingLanguage.C:
                return TrendingLanguage.C;
            case TrendingLanguage.RUBY:
                return TrendingLanguage.RUBY;
            case TrendingLanguage.JAVASCRIPT:
                return TrendingLanguage.JAVASCRIPT;
            case TrendingLanguage.SWIFT:
                return TrendingLanguage.SWIFT;
            case TrendingLanguage.OBJECTIVE_C:
                return TrendingLanguage.OBJECTIVE_C;
            case TrendingLanguage.C_PLUS_PLUS:
                return TrendingLanguage.C_PLUS_PLUS;
            case TrendingLanguage.PYTHON:
                return TrendingLanguage.PYTHON;
            case TrendingLanguage.C_SHARP:
                return TrendingLanguage.C_SHARP;
            case TrendingLanguage.HTML:
                return TrendingLanguage.HTML;
            default:
            case TrendingLanguage.JAVA:
                return TrendingLanguage.JAVA;
        }
    }

    @Override
    public void setDefaultLanguageForTrending(@TrendingLanguage String language) {
        SharedPreferences.Editor editor = mPreferences.edit();
        editor.putString(PREFERENCES_TRENDING_LANGUAGE, language);
        editor.apply();
    }

    @Override
    public
    @TrendingPeriod
    String getDefaultPeriodForTrending() {
        String language = mPreferences.getString(PREFERENCES_TRENDING_PERIOD,
                TrendingPeriod.DAILY);
        switch (language) {
            case TrendingPeriod.DAILY:
                return TrendingPeriod.DAILY;
            case TrendingPeriod.WEEKLY:
                return TrendingPeriod.WEEKLY;
            case TrendingPeriod.MONTHLY:
                return TrendingPeriod.MONTHLY;
            default:
                return TrendingPeriod.DAILY;
        }
    }

    @Override
    public void setDefaultPeriodForTrending(@TrendingPeriod String period) {
        SharedPreferences.Editor editor = mPreferences.edit();
        editor.putString(PREFERENCES_TRENDING_PERIOD, period);
        editor.apply();
    }

    public void saveReferringSites(long repositoryId, List<ReferringSite> referrers) {
        Uri uri = ReferrerContract.ReferrerEntry.CONTENT_URI;

        mContentResolver.delete(uri,
                ReferrerContract.ReferrerEntry.COLUMN_REPOSITORY_KEY + " =  ? ",
                new String[]{String.valueOf(repositoryId)});

        for (ReferringSite referrer : referrers) {
            ContentValues referrerValues = ReferrerContract.ReferrerEntry
                    .createContentValues(repositoryId, referrer);

            mContentResolver.insert(uri, referrerValues);
        }
    }

    @Override
    public void setPinned(boolean active, long id) {
        Uri uri = RepositoryContract.RepositoryEntry.CONTENT_URI;
        ContentValues contentValues = new ContentValues();
        contentValues.put(RepositoryContract.RepositoryEntry.COLUMN_REPOSITORY_PINNED, active ? 1 : 0);
        mContentResolver.update(uri, contentValues,
                RepositoryContract.RepositoryEntry.COLUMN_REPOSITORY_ID + " = "
                        + id, null);
    }

    public boolean saveRepositories(List<Repository> repositories) throws IOException {
        Uri uri = RepositoryContract.RepositoryEntry.CONTENT_URI;
        for (Repository repository : repositories) {
            ContentValues repositoryValues = RepositoryContract.RepositoryEntry.
                    buildContentValues(repository);

            Cursor cursor = mContentResolver.query(uri,
                    new String[]{RepositoryContract.RepositoryEntry.COLUMN_REPOSITORY_ID},
                    RepositoryContract.RepositoryEntry.COLUMN_REPOSITORY_ID + " = "
                            + repository.getId(), null, null);

            if (cursor != null && cursor.moveToFirst()) {
                mContentResolver.update(uri, repositoryValues,
                        RepositoryContract.RepositoryEntry.COLUMN_REPOSITORY_ID + " = "
                                + repository.getId(), null);
            } else {
                mContentResolver.insert(uri, repositoryValues);
            }

            if (cursor != null) {
                cursor.close();
            }
        }
        return true;
    }

    public void saveClones(long repositoryId, Clones clones) {
        Uri uri = ClonesContract.ClonesEntry.CONTENT_URI;

        for (Clones.Clone clone : clones.asList()) {
            ContentValues contentValues = ClonesContract.ClonesEntry
                    .buildContentValues(repositoryId, clone);

            String timestamp = clone.getTimestamp();
            long timeInMilliseconds = TimeConverter.iso8601ToMilliseconds(timestamp);

            String selection = ClonesContract.ClonesEntry.COLUMN_REPOSITORY_KEY + " = "
                    + repositoryId + " AND "
                    + ClonesContract.ClonesEntry.COLUMN_CLONES_TIMESTAMP
                    + " = " + timeInMilliseconds;

            Cursor cursor = mContentResolver.query(uri,
                    new String[]{ClonesContract.ClonesEntry.COLUMN_REPOSITORY_KEY},
                    selection, null, null);

            if (cursor != null && cursor.moveToFirst()) {
                mContentResolver.update(uri, contentValues, selection, null);
            } else {
                mContentResolver.insert(uri, contentValues);
            }

            if (cursor != null) {
                cursor.close();
            }
        }
    }

    public void saveViews(long repositoryId, Views views) {
        Uri uri = ViewsContract.ViewsEntry.CONTENT_URI;

        for (Views.View view : views.getViews()) {
            ContentValues contentValues = ViewsContract.ViewsEntry
                    .buildContentValues(repositoryId, view);

            String timestamp = view.getTimestamp();
            long timeInMilliseconds = TimeConverter.iso8601ToMilliseconds(timestamp);

            String selection = ViewsContract.ViewsEntry.COLUMN_REPOSITORY_KEY + " = "
                    + repositoryId + " AND "
                    + ViewsContract.ViewsEntry.COLUMN_VIEWS_TIMESTAMP
                    + " = " + timeInMilliseconds;

            Cursor cursor = mContentResolver.query(uri,
                    new String[]{ViewsContract.ViewsEntry.COLUMN_REPOSITORY_KEY},
                    selection, null, null);

            if (cursor != null && cursor.moveToFirst()) {
                mContentResolver.update(uri, contentValues, selection, null);
            } else {
                mContentResolver.insert(uri, contentValues);
            }

            if (cursor != null) {
                cursor.close();
            }
        }
    }

    public void saveUser(User user) {
        if (user != null) {
            Uri uri = UserContract.UsersEntry.CONTENT_URI;
            ContentValues contentValues = UserContract.UsersEntry.buildContentValues(user);
            mContentResolver.delete(uri, null, null);
            mContentResolver.insert(uri, contentValues);
        }
    }

    public void saveTrendingRepositories(String period, String language,
                                         List<TrendingRepository> repositories) {
        Uri uri = TrendingContract.TrendingEntry.CONTENT_URI;

        ArrayList<ContentProviderOperation> ops = new ArrayList<>();

        ops.add(ContentProviderOperation.newDelete(uri)
                .withSelection(TrendingContract.TrendingEntry.COLUMN_LANGUAGE + " = ? AND " +
                                TrendingContract.TrendingEntry.COLUMN_PERIOD + " = ? ",
                        new String[]{language, period}).build());

        for (TrendingRepository repository : repositories) {

            repository.setLanguage(language);
            repository.setPeriod(period);

            ContentValues contentValues = TrendingContract.TrendingEntry
                    .buildContentValues(repository, period, language);
            ops.add(ContentProviderOperation.newInsert(uri)
                    .withValues(contentValues).build());
        }
        try {
            mContentResolver.applyBatch(TrendingContract.CONTENT_AUTHORITY, ops);
            mContentResolver.notifyChange(uri, null);
        } catch (RemoteException | OperationApplicationException e) {
            FirebaseCrash.report(e);
        }
    }

    public void saveStargazers(Repository repository, List<Star>
            starList) {
        Uri uri = StargazersContract.Entry.CONTENT_URI;

        for (Star stargazers : starList) {
            if (stargazers != null) {

                ContentValues contentValues = StargazersContract.Entry
                        .buildContentValues(repository.getId(), stargazers);

                String starredAd = stargazers.getStarredAt();
                long timeInMilliseconds = TimeConverter.iso8601ToMilliseconds(starredAd);

                String selection = StargazersContract.Entry.COLUMN_REPOSITORY_KEY + " = "
                        + repository.getId() + " AND "
                        + StargazersContract.Entry.COLUMN_TIMESTAMP
                        + " = " + timeInMilliseconds;

                Cursor cursor = mContentResolver.query(uri,
                        new String[]{StargazersContract.Entry.COLUMN_REPOSITORY_KEY},
                        selection, null, null);

                if (cursor == null || !cursor.moveToFirst()) {
                    mContentResolver.insert(uri, contentValues);
                }

                if (cursor != null) {
                    cursor.close();
                }
            }
        }
    }

    @Retention(SOURCE)
    @StringDef({TrendingPeriod.DAILY, TrendingPeriod.WEEKLY, TrendingPeriod.MONTHLY})
    public @interface TrendingPeriod {
        String DAILY = "daily";
        String WEEKLY = "weekly";
        String MONTHLY = "monthly";
    }

    @Retention(SOURCE)
    @StringDef({TrendingLanguage.JAVA,
            TrendingLanguage.C,
            TrendingLanguage.RUBY,
            TrendingLanguage.JAVASCRIPT,
            TrendingLanguage.SWIFT,
            TrendingLanguage.OBJECTIVE_C,
            TrendingLanguage.C_PLUS_PLUS,
            TrendingLanguage.PYTHON,
            TrendingLanguage.C_SHARP,
            TrendingLanguage.HTML})
    public @interface TrendingLanguage {
        String JAVA = "Java";
        String C = "C";
        String RUBY = "Ruby";
        String JAVASCRIPT = "Javascript";
        String SWIFT = "Swift";
        String OBJECTIVE_C = "Objective-C";
        String C_PLUS_PLUS = "C++";
        String PYTHON = "Python";
        String C_SHARP = "C#";
        String HTML = "Html";
    }
} public class Utils {

    /**
     * The {@code fragment} is added to the container view with id {@code frameId}. The operation is
     * performed by the {@code fragmentManager}.
     */
    public static void addFragmentToActivity(@NonNull FragmentManager fragmentManager,
                                             @NonNull Fragment fragment, int frameId) {
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.add(frameId, fragment);
        transaction.commitAllowingStateLoss();
    }

    public static void replaceFragment(@NonNull FragmentManager fragmentManager,
                                       @NonNull Fragment fragment, int frameId) {
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(frameId, fragment);
        transaction.commitAllowingStateLoss();
    }

    public static void openFeedback(Activity activity) {
        try {
            throw new IOException();
        } catch (IOException e) {
            ApplicationErrorReport report = new ApplicationErrorReport();
            report.packageName = report.processName = activity.getApplication()
                    .getPackageName();
            report.time = System.currentTimeMillis();
            report.type = ApplicationErrorReport.TYPE_CRASH;
            report.systemApp = false;
            ApplicationErrorReport.CrashInfo crash = new ApplicationErrorReport.CrashInfo();
            crash.exceptionClassName = e.getClass().getSimpleName();
            crash.exceptionMessage = e.getMessage();
            StringWriter writer = new StringWriter();
            PrintWriter printer = new PrintWriter(writer);
            e.printStackTrace(printer);
            crash.stackTrace = writer.toString();
            StackTraceElement stack = e.getStackTrace()[0];
            crash.throwClassName = stack.getClassName();
            crash.throwFileName = stack.getFileName();
            crash.throwLineNumber = stack.getLineNumber();
            crash.throwMethodName = stack.getMethodName();
            report.crashInfo = crash;
            Intent intent = new Intent(Intent.ACTION_APP_ERROR);
            intent.putExtra(Intent.EXTRA_BUG_REPORT, report);
            activity.startActivity(intent);
        }
    }

    public static boolean isNetworkAvailable() {
        Context context = GitoApplication.context();
        ConnectivityManager connectivityManager
                = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        return activeNetworkInfo != null && activeNetworkInfo.isConnected();
    }

    public static void openSettings(Activity activity) {
        Intent intent = new Intent(activity, SettingsActivity.class);
        activity.startActivity(intent);
    }

    @SuppressWarnings("deprecation")
    public static Drawable getColor(Context context, String language) {
        Resources resources = context.getResources();

        if (language == null) {
            return resources.getDrawable(R.drawable.shape_oval_java);
        }

        switch (language) {
            case GithubLocalDataSource.TrendingLanguage.C:
                return resources.getDrawable(R.drawable.shape_oval_c);
            case GithubLocalDataSource.TrendingLanguage.RUBY:
                return resources.getDrawable(R.drawable.shape_oval_ruby);
            case GithubLocalDataSource.TrendingLanguage.JAVASCRIPT:
                return resources.getDrawable(R.drawable.shape_oval_javascript);
            case GithubLocalDataSource.TrendingLanguage.SWIFT:
                return resources.getDrawable(R.drawable.shape_oval_swift);
            case GithubLocalDataSource.TrendingLanguage.OBJECTIVE_C:
                return resources.getDrawable(R.drawable.shape_oval_objective_c);
            case GithubLocalDataSource.TrendingLanguage.C_PLUS_PLUS:
                return resources.getDrawable(R.drawable.shape_oval_c_plus);
            case GithubLocalDataSource.TrendingLanguage.PYTHON:
                return resources.getDrawable(R.drawable.shape_oval_python);
            case GithubLocalDataSource.TrendingLanguage.C_SHARP:
                return resources.getDrawable(R.drawable.shape_oval_c_sharp);
            case GithubLocalDataSource.TrendingLanguage.HTML:
                return resources.getDrawable(R.drawable.shape_oval_html);
            default:
            case GithubLocalDataSource.TrendingLanguage.JAVA:
                return resources.getDrawable(R.drawable.shape_oval_java);
        }
    }

    public static long today() {
        Calendar c = new GregorianCalendar(TimeConverter.getGitHubDefaultTimeZone());
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH);
        int day = c.get(Calendar.DAY_OF_MONTH);
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month, day, 0, 0, 0);
        return calendar.getTimeInMillis() / 1000 * 1000;
    }

    public static long yesterday() {
        Calendar c = new GregorianCalendar(TimeConverter.getGitHubDefaultTimeZone());
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH);
        int day = c.get(Calendar.DAY_OF_MONTH);
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month, day - 1, 0, 0, 0);
        return calendar.getTimeInMillis() / 1000 * 1000;
    }

    public static long twoWeeksAgo() {
        Calendar c = new GregorianCalendar(TimeConverter.getGitHubDefaultTimeZone());
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH);
        int day = c.get(Calendar.DAY_OF_MONTH);
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month, day - 14, 0, 0, 0);
        return calendar.getTimeInMillis() / 1000 * 1000;
    }

    public static long weekAgo() {
        Calendar c = new GregorianCalendar(TimeConverter.getGitHubDefaultTimeZone());
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH);
        int day = c.get(Calendar.DAY_OF_MONTH);
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month, day - 7, 0, 0, 0);
        return calendar.getTimeInMillis() / 1000 * 1000;
    }

    public static String humanReadable(long timestamp) {
        DateFormat dateFormat = new SimpleDateFormat("dd.MM", Locale.US);
        Date date = new Date(timestamp);
        return dateFormat.format(date);
    }
} public class GitHubAPI {

    private GitHubAPI() {
    }

    public static TrafficService traffic() {
        return new TrafficService();
    }

    public static RepositoryService repository() {
        return new RepositoryService();
    }

    public static UserService user() {
        return new UserService();
    }

    public static StargazersService stargazers() {
        return new StargazersService();
    }

    public static AuthenticationBuilder auth() {
        return new AuthenticationBuilder();
    }

    public static ExploreBuilder trending() {
        return new ExploreBuilder();
    }
} public class Service {
    public static final String API_URL_AUTH = "https://github.com/login/oauth/authorize/";
    static final String API_HTTPS_BASE_URL = "https://api.github.com/";
    private static final String API_BASE_URL = "https://github.com/";
    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
    private AccessToken mAccessToken = new AccessToken();

    Service() {
    }

    public Service setToken(String token) {
        mAccessToken.setAccessToken(token);
        return this;
    }

    public Service setTokenType(String tokenType) {
        mAccessToken.setTokenType(tokenType);
        return this;
    }

    AccessToken getAccessToken() {
        return mAccessToken;
    }

    <S> S createService(Class<S> serviceClass) {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        //interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .addInterceptor(new Interceptor() {
                    @Override
                    public okhttp3.Response intercept(Chain chain) throws IOException {
                        Request original = chain.request();
                        Request.Builder requestBuilder = original.newBuilder()
                                .header("Accept", "application/json")
                                .method(original.method(), original.body());
                        Request request = requestBuilder.build();
                        return chain.proceed(request);
                    }
                })
                .build();
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(API_BASE_URL)
                .addConverterFactory(GsonConverterFactory.create()).client(client).build();
        return retrofit.create(serviceClass);
    }

    <S> S createService(Class<S> serviceClass, @NonNull final AccessToken token,
                        String baseUrl, final String headerAccept) {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        //interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = httpClient
                .addInterceptor(interceptor)
                .addInterceptor(new Interceptor() {
                    @Override
                    public okhttp3.Response intercept(Chain chain) throws IOException {
                        Request original = chain.request();
                        Request.Builder requestBuilder = original.newBuilder()
                                .header("Accept", headerAccept)
                                .header("Authorization",
                                        token.getTokenType() + " " + token.getToken())
                                .method(original.method(), original.body());
                        Request request = requestBuilder.build();
                        return chain.proceed(request);
                    }
                })
                .build();
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create()).client(client).build();
        return retrofit.create(serviceClass);
    }

    /**
     * Client Errors: https://developer.github.com/v3/
     */
    @SuppressWarnings("all")
    public static class APIError {

        @SerializedName("message")
        private String mMessage = "No internet connection";

        public static APIError parseError(Response<?> response) {
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(API_HTTPS_BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(new OkHttpClient.Builder().build()).build();

            Converter<ResponseBody, APIError> converter =
                    retrofit.responseBodyConverter(APIError.class, new Annotation[0]);

            APIError error;

            try {
                error = converter.convert(response.errorBody());
            } catch (IOException e) {
                return new APIError();
            }

            return error;
        }

        public String getMessage() {
            return mMessage;
        }
    }

    public class Pagination {

        public static final String LAST_PAGE = "last";
        private static final String HEADER_LINK = "Link";
        private int mLastPage;

        public void parse(Response<List<Star>> response) {
            String headerLink = response.headers().get(HEADER_LINK);
            if (headerLink != null) {
                headerLink = headerLink.replace(
                        headerLink.substring(headerLink.lastIndexOf(">")), "");
                mLastPage = Integer.valueOf(headerLink.replace(
                        headerLink.substring(0, headerLink.lastIndexOf("=") + 1), ""));
            }
        }

        int getLastPage() {
            return mLastPage;
        }
    }
} @SuppressWarnings("all")
public class AccessToken {

    @SerializedName("access_token")
    private String mAccessToken;
    @SerializedName("token_type")
    private String mTokenType;

    public String getToken() {
        return mAccessToken;
    }

    public String getTokenType() {
        return mTokenType;
    }

    public void setTokenType(String tokenType) {
        this.mTokenType = tokenType;
    }

    public void setAccessToken(String accessToken) {
        this.mAccessToken = accessToken;
    }
} @SuppressWarnings("all")
public class Clones {
    @SerializedName("count")
    private String mCount;

    @SerializedName("uniques")
    private String mUniques;

    @SerializedName("clones")
    private List<Clone> mClones;

    public List<Clone> asList() {
        return mClones;
    }

    public static class Clone {
        @SerializedName("timestamp")
        private String mTimestamp;

        @SerializedName("count")
        private String mCount;

        @SerializedName("uniques")
        private String mUniques;

        public String getTimestamp() {
            return mTimestamp;
        }

        public String getCount() {
            return mCount;
        }

        public String getUniques() {
            return mUniques;
        }
    }
} @SuppressWarnings("all")
public class ReferringSite {

    @SerializedName("referrer")
    private String mReferrer;

    @SerializedName("count")
    private int mCount;

    @SerializedName("uniques")
    private int mUniques;

    public String getReferrer() {
        return mReferrer;
    }

    public int getCount() {
        return mCount;
    }

    public int getUniques() {
        return mUniques;
    }
} @SuppressWarnings("all")
public class Star {

    @SerializedName("user")
    public User mUser;
    @SerializedName("starred_at")
    private String mStarredAt;

    public String getStarredAt() {
        return mStarredAt;
    }

    private class User {
        @SerializedName("id")
        private long mId;

        @SerializedName("login")
        private String mLogin;

        @SerializedName("url")
        private String mUrl;

        public long getId() {
            return mId;
        }

        public String getLogin() {
            return mLogin;
        }

        public String getUrl() {
            return mUrl;
        }
    }
} @SuppressWarnings("all")
public class TrendingRepository {

    @SerializedName("avatar")
    String mAvatar;

    @SerializedName("repo")
    String mRepo;

    @SerializedName("desc")
    String description;

    @SerializedName("owner")
    String mOwner;

    @SerializedName("stars")
    String mStars;

    @SerializedName("link")
    String mHtmlUrl;

    String mLanguage;

    String mPeriod;

    public String getName() {
        return mRepo;
    }

    public String getDescription() {
        return description;
    }

    public String getOwner() {
        return mOwner;
    }

    public String getWatchersCount() {
        return mStars;
    }

    public String getHtmlUrl() {
        return mHtmlUrl;
    }

    public String getAvatar() {
        return mAvatar;
    }

    public String getLanguage() {
        return mLanguage;
    }

    public void setLanguage(String language) {
        mLanguage = language;
    }

    public String getPeriod() {
        return mPeriod;
    }

    public void setPeriod(String period) {
        mPeriod = period;
    }
} @SuppressWarnings("all")
public class User {

    String mLogin;
    String mName;
    String mAvatarUrl;
    String mFollowers;

    public String getLogin() {
        return mLogin;
    }

    public void setLogin(String login) {
        mLogin = login;
    }

    public String getName() {
        return mName;
    }

    public void setName(String name) {
        mName = name;
    }

    public String getAvatarUrl() {
        return mAvatarUrl;
    }

    public void setAvatarUrl(String avatarUrl) {
        mAvatarUrl = avatarUrl;
    }

    public String getFollowers() {
        return mFollowers;
    }

    public void setFollowers(String followers) {
        mFollowers = followers;
    }
} @SuppressWarnings("all")
public class Views {
    @SerializedName("count")
    private String mCount;

    @SerializedName("uniques")
    private String mUniques;

    @SerializedName("views")
    private List<View> mViews;

    public List<View> getViews() {
        return mViews;
    }

    public static class View {
        @SerializedName("timestamp")
        private String mTimestamp;

        @SerializedName("count")
        private String mCount;

        @SerializedName("uniques")
        private String mUniques;

        public String getTimestamp() {
            return mTimestamp;
        }

        public String getCount() {
            return mCount;
        }

        public String getUniques() {
            return mUniques;
        }
    }
}
import android.content.ContentResolver;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.support.annotation.WorkerThread;
import android.util.Log;
import com.dmitrymalkovich.android.githubanalytics.data.source.GithubDataSource;
import com.dmitrymalkovich.android.githubanalytics.data.source.local.GithubLocalDataSource;
import com.dmitrymalkovich.android.githubanalytics.Utils;
import com.dmitrymalkovich.android.githubapi.GitHubAPI;
import com.dmitrymalkovich.android.githubapi.core.Service;
import com.dmitrymalkovich.android.githubapi.core.data.AccessToken;
import com.dmitrymalkovich.android.githubapi.core.data.Clones;
import com.dmitrymalkovich.android.githubapi.core.data.ReferringSite;
import com.dmitrymalkovich.android.githubapi.core.data.Star;
import com.dmitrymalkovich.android.githubapi.core.data.TrendingRepository;
import com.dmitrymalkovich.android.githubapi.core.data.User;
import com.dmitrymalkovich.android.githubapi.core.data.Views;
import com.google.firebase.crash.FirebaseCrash;
import org.eclipse.egit.github.core.Repository;
import org.eclipse.egit.github.core.client.RequestException;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
                                                       List<Repository> repositories) {
        if (repositories != null) {
            for (Repository repository : repositories) {
                if (repository.getId() == repositoryId) {
                    getRepositoryReferrersSync(repository);
                    getRepositoryViewsSync(repository, "day");
                    getRepositoryClonesSync(repository, "day");
                    getStargazersSync(repository);
                }
            }
        }
    }

    @Override
    public void getRepositoriesWithAdditionalInfo(final GetRepositoriesCallback callback, boolean useCache) {
        new AsyncTask<Void, Void, List<Repository>>() {
            @Override
            protected List<Repository> doInBackground(Void... params) {
                List<Repository> repositories = getRepositoriesSync();
                getRepositoriesWithAdditionalInfoSync(repositories);
                return repositories;
            }

            @Override
            protected void onPostExecute(List<Repository> repositoryList) {
                if (repositoryList != null) {
                    callback.onRepositoriesLoaded(repositoryList);
                } else {
                    callback.onDataNotAvailable();
                }
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    @Override
    public void getRepositoriesWithAdditionalInfo(final long repositoryId,
                                                  final GetRepositoriesCallback callback, boolean useCache) {
        new AsyncTask<Void, Void, List<Repository>>() {
            @Override
            protected List<Repository> doInBackground(Void... params) {
                List<Repository> repositories = getRepositoriesSync();
                getRepositoriesWithAdditionalInfoSync(repositoryId, repositories);
                return repositories;
            }

            @Override
            protected void onPostExecute(List<Repository> repositoryList) {
                if (repositoryList != null) {
                    callback.onRepositoriesLoaded(repositoryList);
                } else {
                    callback.onDataNotAvailable();
                }
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    @WorkerThread
    private Clones getRepositoryClonesSync(final Repository repository, String period) {
        try {
            Clones clones = GitHubAPI.traffic()
                    .setToken(getToken())
                    .setTokenType(getTokenType())
                    .setRepository(repository)
                    .setPeriod(period)
                    .getClones();

            mLocalDataSource.saveClones(repository.getId(), clones);

            return clones;

        } catch (IOException e) {
            Log.e(LOG_TAG, e.getMessage(), e);
            return null;
        }
    }

    @Override
    public void getRepositoryClones(final Repository repository, final String period,
                                    final GetRepositoryClonesCallback callback) {
        new AsyncTask<Void, Void, Clones>() {
            @Override
            protected Clones doInBackground(Void... params) {
                return getRepositoryClonesSync(repository, period);
            }

            @Override
            protected void onPostExecute(Clones clones) {
                if (clones != null) {
                    callback.onRepositoryClonesLoaded(clones);
                } else {
                    callback.onDataNotAvailable();
                }
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    @WorkerThread
    private Views getRepositoryViewsSync(final Repository repository, String period) {
        try {
            Views views = GitHubAPI.traffic()
                    .setToken(getToken())
                    .setTokenType(getTokenType())
                    .setRepository(repository)
                    .setPeriod(period)
                    .getViews();

            mLocalDataSource.saveViews(repository.getId(), views);
            return views;

        } catch (IOException e) {
            if (Utils.isNetworkAvailable()) {
                FirebaseCrash.report(e);
            }
            return null;
        }
    }

    @WorkerThread
    public void getUserSync() {
        try {
            User user = GitHubAPI.user()