Category: Blog

  • mflowd

    Metrics Flow Daemon Build Status Go Report

    It is a small daemon that aggregates custom monitoring metrics collected from Google Dataflow workers that use metrics-flow library and exposes them to Prometheus.

    How it works

    Google Dataflow workers with metrics-flow plugged in pre-aggregate custom monitoring metrics using pipeline windowing functions and dump the results into a Google Pub/Sub topic. The metrics flow daemon polls a subscription to the topic, converts received metric update events to Prometheus format and exposes them through /metrics endpoint.

    +------------+                                                      
    | Dataflow 1 +----+                                                 
    +------------+    |                                                 
                      |                                                 
    +------------+    |                       +------------+            
    | Dataflow i |----|->(Google Pub/Sub)---->|   mflowd   |            
    +------------+    |                       +------------+            
                      |                              ^                  
    +------------+    |                              |                  
    | Dataflow N |----+                       +-------------+           
    +------------+                            | Prometheus  |           
                                              +-------------+           
    

    Installation

    % go get github.com/QubitProducts/mflowd
    

    Build it from scratch

    1. Make sure you have dep installed (if you don’t know how to install it, follow this link)
    2. make bootstrap
    3. make test
    4. make mflowd

    Running

    1. Create a pub/sub topic you will use for publishing metrics from your Dataflow workers (if you don’t have one already).

    2. Create a pull subscription to the topic

    3. Make sure you are authorized to use the subscription (if not sure, use gcloud auth login)

    4. Run the daemon

      % ./mflowd [-v] -p <port> -s pubsub <subscription_id>
      

    Where

    • port is a port where /metrics endpoint will be exposed
    • subscription_path is a subscription identifier which usually looks like projects/<project_name>/subscriptions/<subcsciption_name>
    • use optional -v flag to run the daemon in verbose mode

    Using Docker

    You can easily build a “containerized” version of mflowd and run it on mesos or kubernetes.

    Building

    % make docker
    % docker images | grep mflowd
    mflowd                                             latest                                            e9cbac93f703
    ...
    

    Running

    Before you can run the image you need to set up a Google Cloud API service account to allow mflowd use the subscription you have created. So

    1. Create a service account for mflowd

    2. Create an empty directory on your host machine (say, % mkdir ~/.mflowd)

    3. Download the service account key in JSON format and put it to the created directory

    4. Finally run the countainer:

      % docker run -e "MFLOWD_SUB=<subscription_id>" -v $HOME/.mflowd:/etc/mflowd 'mflowd:latest'
      

    Using docker-compose

    You can also run both mflowd and prometheus docker images using docker-compose:

    % cd ~/go/src/github.com/QubitProducts/mflowd
    % mkdir gcp
    # download your service account JSON key to gcp directory
    % cat > .env
    MFLOWD_SUB=<subscription_id>
    MFLOWD_VERBOSE=0 # set to 1 to turn verbose mode on
    ^C
    % docker-compose up
    

    Follow http://localhost:9090 to get to Prometheus UI

    Visit original content creator repository
  • NFT_Staking_app

    StakeSphere

    Overview

    StakeSphere is an NFT Staking Application that allows users to connect their wallets, claim an NFT (if they don’t have one), stake their NFTs for rewards, and withdraw staked NFTs. The application also provides staking rewards for staked NFTs, incentivizing users to participate actively. The app ensures secure blockchain interactions through a streamlined process involving two transactions for approval and staking.

    Dashboard


    Features

    • Wallet Connection: Users can connect their wallets to interact with the application.
    • NFT Claiming: Users who do not own any NFTs can claim one to begin staking.
    • NFT Staking: Stake NFTs securely to earn rewards.
    • NFT Withdrawal: Withdraw any NFT that has been staked at any time.
    • Staking Rewards: Users earn rewards for the duration their NFTs are staked.
    • Transaction Flow: Two transactions are performed during staking:
      1. Approval of the NFT for staking.
      2. Staking of the NFT.

    WalletIntegration WalletIntegration WalletIntegration

    Tech Stack

    • Frontend: Next.js for server-rendered React applications.
    • Styling: TailwindCSS for a responsive and modern UI.
    • Blockchain SDK: Thirdweb for NFT and blockchain interaction.
    • Language: TypeScript for type-safe development.

    Dashboard Dashboard

    Installation and Setup

    Prerequisites

    • Node.js and npm installed on your machine.
    • Wallet provider (e.g., MetaMask) installed and configured.
    • Access to a blockchain network supporting NFTs (e.g., Ethereum or Polygon).

    Transaction Approval

    Steps

    1. Clone the repository:

      git clone https://github.com/your-repo/stakesphere.git
      cd stakesphere
    2. Install dependencies:

      npm install
    3. Configure environment variables: Create a .env.local file in the root directory and add your blockchain provider, Thirdweb API keys, and other required credentials.

    4. Start the development server:

      npm run dev
    5. Open the application in your browser at http://localhost:3000.


    How It Works

    Transaction Request

    1. Connect Wallet: Users connect their wallet using the wallet connect button. Supported wallets include MetaMask, Coinbase Wallet, and others.

    2. Claim NFT: If a user doesn’t own any NFT, they can claim one via the “Claim NFT” button. The application checks the user’s wallet before allowing staking.

    3. Stake NFT:

      • Users select an NFT from their wallet.
      • The app prompts two transactions:
        1. Approval of the NFT.
        2. Staking of the NFT.
      • Once staked, users begin earning rewards.
    4. Withdraw NFT: Users can withdraw any staked NFT back to their wallet. Rewards are calculated and distributed based on the staking duration.


    No NFT Stake

    Folder Structure

    src/
    |-- components/     # Reusable UI components
    |-- pages/          # Application pages (Next.js routing)        
    |-- utils/          # blockchain abi and address
    

    Future Enhancements

    • Support for multiple NFT collections.
    • Detailed analytics for staking activities.
    • Integration with additional blockchain networks.
    • Enhanced reward calculation algorithms.

    Contributing

    Contributions are welcome! Please fork the repository, create a feature branch, and submit a pull request. Ensure your code follows the project’s coding standards.


    Acknowledgements

    • Thirdweb for simplifying blockchain interactions.
    • TailwindCSS for a beautiful and responsive UI.
    • Next.js for a seamless development experience.

    Visit original content creator repository
  • reddit-auto-reply

    reddit-auto-reply

    Reddit auto reply and auto downvote.

    A script which recurrsively walks over a specific post and
    automatically replies to (and downvotes) comments by a particular
    author.

    Have you ever attempted to have a regular decent conversation on
    reddit like any normal human being would, only to be confronted by
    a troll, a moron, or a jerk? Maybe this person is just genuinely
    evil. Maybe this person just won’t let you have the last word?
    It’s probably because their mother didn’t teach them good manners.

    This script could enable you to repetitively shut this person down
    without having to spare them even a single thought.

    This is a mostly untested sript. I only wrote it to end a certain
    conversation. It did a fine job at that, and it kept me from having
    to waste any more time replying to that thread. I fed the script
    a reply that made it quite clear that the person that I was replying
    to was deficient in their mental capacities and that I had written
    this bot to automatically reply to anything they wrote in my thread.
    It worked perfectly. After a few rounds of interacting with my
    reply bot, that person finally realized that they would never have
    the last word. They moved on and dug a little deeper into their
    troll hole. Good riddance.

    usage

    First install the packages using pip or whatever. You can use a
    virtualenv if you want of course.

    Run the program with the following command
    python3 reddit_auto_reply.py

    Currently you have to edit the script manually, filling in the
    necessary details by editing certain variables manually. You
    should be able to tell which variables need to be edited by going
    into the program and reading the code. If you want to know more
    about what variables you need to edit or how to do so, create an
    issue and let me know. I’m willing to put a small amount of work
    into this to make it better and more usable.

    Visit original content creator repository

  • Football-xG-Predictor

    ⚽ Football Expected Goals (xG) Predictor

    🧠 About the Project

    An Expected Goals (xG) model that predicts the probability of scoring based on StatsBomb data. The project uses machine learning techniques to analyze factors most influencing shot effectiveness in football. Applied models (Logistic Regression, Random Forest, XGBoost) combined with Beta calibration technique create a highly accurate predictive tool. Analysis results confirm the crucial role of shot geometry and defender influence on goal-scoring probability.

    🎯 Motivation

    Expected Goals (xG) is one of the most important metrics used in modern football analytics. It allows for evaluating shot quality regardless of whether they resulted in a goal. In this project, I built my own xG model to better understand factors affecting shot effectiveness and create a tool that can be used for match analysis and player evaluation.

    📋 Data

    The data used comes from StatsBomb’s open dataset from the 2015/2016 season for five top European leagues:

    • Premier League (England)
    • La Liga (Spain)
    • Bundesliga (Germany)
    • Serie A (Italy)
    • Ligue 1 (France)

    The data contains detailed information about each shot, including position on the pitch, shot type, circumstances of the shot, and positioning of other players at the moment of the shot.

    Note: The repository does not include data files by default. You need to run the data_collector.ipynb notebook first to download the data from StatsBomb’s open dataset.

    https://github.com/statsbomb/open-data

    🔍 Methodology

    Data Preparation

    • Extraction of relevant shot-related variables
    • Transformation of raw location data into useful geometric features
    • Categorization of shot types and body parts used for shots

    Feature Engineering

    • Geometric: shot angle, distance from goal
    • Contextual: number of defenders on shot line, goalkeeper presence
    • Technical: dominant vs non-dominant foot shots, first-time shots
    • Situational: shots under pressure, shots after dribbling

    Modeling

    Testing and comparison of three algorithms:

    1. Logistic Regression
    2. Random Forest
    3. XGBoost

    Model Calibration

    Application of Beta Calibration technique to calibrate probabilities, which significantly improved model prediction quality.

    📈 Key Results

    Model Comparison

    Model ROC AUC Brier Score Log Loss xG/Goals Ratio
    Logistic Regression 0.796 0.073 0.257 0.98
    Random Forest 0.796 0.074 0.259 0.99
    XGBoost 0.798 0.073 0.257 0.98

    Key Findings

    1. Shot geometry is crucial – shot angle and distance from goal are the strongest predictors
    2. Defenders on shot line – each additional defender significantly decreases goal-scoring probability
    3. First-time shots have higher effectiveness than those preceded by ball control
    4. Model calibration is crucial – all models before calibration significantly overestimated probabilities

    💻 Technologies

    • Language: Python 3.7+
    • Data Analysis: Pandas, NumPy
    • ML Models: Scikit-learn, XGBoost
    • Visualization: Matplotlib, Seaborn, Mplsoccer
    • Data Source: StatsBombPy

    📁 Project Structure

    Football-xG-Predictor/
    ├── notebooks/                 
    │   ├── data_collection.py      # Data collection script
    │   └── xg_model.ipynb          # Main notebook with xG model
    ├── src/                        
    │   ├── __init__.py             # Package initialization file
    │   ├── preprocessing.py        # Data preprocessing functions
    │   ├── feature_engineering.py  # Feature engineering
    │   ├── modeling.py             # Model implementation
    │   ├── evaluation.py           # Metrics and model evaluation
    │   └── visualization.py        # Visualizations
    ├── data/                       # Data folder (created after running data_collector.ipynb)
    ├── assets/                     # Graphics and visualizations
    ├── requirements.txt            # Dependencies
    └── README.md                   # Project description / this file
    

    🚀 How to Download and Run the Project

    1. Clone the repository:
    git clone https://github.com/bsobkowicz1096/Football-xG-Predictor.git
    1. Navigate to the project directory:
    cd Football-xG-Predictor
    1. Create a virtual environment (optional but recommended):

    python -m venv venv
    source venv/bin/activate  # On Linux/macOS
    venv\Scripts\activate     # On Windows
    1. Install dependencies:
    pip install -r requirements.txt
    1. Run the notebook:
    jupyter notebook notebooks/football_xg_predictor.ipynb

    Note: The project uses publicly available StatsBomb data, used in accordance with their license terms.

    Visit original content creator repository

  • Reachability

    Reference Status
    build-status

    WARNING there have been reports of apps being rejected when Reachability is used in a framework. The only solution to this so far is to rename the class.

    Reachability

    This is a drop-in replacement for Apple’s Reachability class. It is ARC-compatible, and it uses the new GCD methods to notify of network interface changes.

    In addition to the standard NSNotification, it supports the use of blocks for when the network becomes reachable and unreachable.

    Finally, you can specify whether a WWAN connection is considered “reachable”.

    DO NOT OPEN BUGS UNTIL YOU HAVE TESTED ON DEVICE

    BEFORE YOU OPEN A BUG ABOUT iOS6/iOS5 build errors, use Tag 3.2 or 3.1 as they support assign types

    Requirements

    Once you have added the .h/m files to your project, simply:

    • Go to the Project->TARGETS->Build Phases->Link Binary With Libraries.
    • Press the plus in the lower left of the list.
    • Add SystemConfiguration.framework.

    Boom, you’re done.

    Examples

    Block Example

    This sample uses blocks to notify when the interface state has changed. The blocks will be called on a BACKGROUND THREAD, so you need to dispatch UI updates onto the main thread.

    In Objective-C

    // Allocate a reachability object
    Reachability* reach = [Reachability reachabilityWithHostname:@"www.google.com"];
    
    // Set the blocks
    reach.reachableBlock = ^(Reachability*reach)
    {
        // keep in mind this is called on a background thread
        // and if you are updating the UI it needs to happen
        // on the main thread, like this:
    
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"REACHABLE!");
        });
    };
    
    reach.unreachableBlock = ^(Reachability*reach)
    {
        NSLog(@"UNREACHABLE!");
    };
    
    // Start the notifier, which will cause the reachability object to retain itself!
    [reach startNotifier];

    In Swift 3

    import Reachability
    
    var reach: Reachability?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
            // Allocate a reachability object
            self.reach = Reachability.forInternetConnection()
            
            // Set the blocks
            self.reach!.reachableBlock = {
                (reach: Reachability?) -> Void in
                
                // keep in mind this is called on a background thread
                // and if you are updating the UI it needs to happen
                // on the main thread, like this:
                DispatchQueue.main.async {
                    print("REACHABLE!")
                }
            }
            
            self.reach!.unreachableBlock = {
                (reach: Reachability?) -> Void in
                print("UNREACHABLE!")
            }
            
            self.reach!.startNotifier()
        
            return true
    }

    NSNotification Example

    This sample will use NSNotifications to notify when the interface has changed. They will be delivered on the MAIN THREAD, so you can do UI updates from within the function.

    In addition, it asks the Reachability object to consider the WWAN (3G/EDGE/CDMA) as a non-reachable connection (you might use this if you are writing a video streaming app, for example, to save the user’s data plan).

    In Objective-C

    // Allocate a reachability object
    Reachability* reach = [Reachability reachabilityWithHostname:@"www.google.com"];
    
    // Tell the reachability that we DON'T want to be reachable on 3G/EDGE/CDMA
    reach.reachableOnWWAN = NO;
    
    // Here we set up a NSNotification observer. The Reachability that caused the notification
    // is passed in the object parameter
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(reachabilityChanged:)
                                                 name:kReachabilityChangedNotification
                                               object:nil];
    
    [reach startNotifier];

    In Swift 3

    import Reachability
    
    var reach: Reachability?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Allocate a reachability object
        self.reach = Reachability.forInternetConnection()
        
        // Tell the reachability that we DON'T want to be reachable on 3G/EDGE/CDMA
        self.reach!.reachableOnWWAN = false
        
        // Here we set up a NSNotification observer. The Reachability that caused the notification
        // is passed in the object parameter
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(reachabilityChanged),
            name: NSNotification.Name.reachabilityChanged,
            object: nil
        )
        
        self.reach!.startNotifier()
        
        return true
    }
            
    func reachabilityChanged(notification: NSNotification) {
        if self.reach!.isReachableViaWiFi() || self.reach!.isReachableViaWWAN() {
            print("Service available!!!")
        } else {
            print("No service available!!!")
        }
    }

    Tell the world

    Head over to Projects using Reachability and add your project for “Maximum Wins!”.

    Visit original content creator repository

  • xxf_android

    Table of Contents

    Android技术中台

    xxf架构封装常用组件与用法,且符合函数式和流式编程

    1. 去除RxLife,用Android自带的lifecycle来管理RxJava的生命周期
    2. viewModel中也可以使用rxjava bind生命周期,跟activity一样,可以处理rxjava的生命周期
    3. 权限请求可以用RxJava链式调用,不用写复杂的回调 内部使用ActivityResultLauncher 且可以免注册
    4. startActivityForResult可以用RxJava链式调用,不用写复杂的回调 内部使用ActivityResultLauncher 且可以免注册
    5. 简单配置http,轻松完成网络请求
    6. http双缓存(避免服务器不处理etag),多种策略保证数据及时交互
    7. 时间和货币格式化全权交割给框架处理
    8. 各种工具类Number,Time,File,Toast,Zip,Arrays….等15种
    9. 全面转向kotlin 扩展函数超 400 个 全部开箱即可使用
    10. 封装常见自定义View
      TitleBar,Loading,ScaleFrameLayout,MaxHeightView,SoftKeyboardSizeWatchLayout…等20种
    11. 数据库在objectbox上进行封装以及监听,以及生成long id

    用法

    引入方式

    代码已经80%转换成kotlin 请注意用法改变,新版本使用方式

    //请在build.gradle中配置
    allprojects {
        repositories {
            maven { url "https://jitpack.io" }
            jcenter()
            maven {
                url 'https://maven.aliyun.com/repository/public'
            }
            maven {
                credentials {
                    username '654f4d888f25556ebb4ed790'
                    password 'OsVOuR6WZFK='
                }
                url 'https://packages.aliyun.com/maven/repository/2433389-release-RMv0jP/'
            }
            maven {
                credentials {
                    username '654f4d888f25556ebb4ed790'
                    password 'OsVOuR6WZFK='
                }
                url 'https://packages.aliyun.com/maven/repository/2433389-snapshot-Kqt8ID/'
            }
        }
        configurations.all {
            // 实时检查 Snapshot 更新
            resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
        }
    }

       //新版本使用方式,需要添加上面的权限
       implementation 'com.NBXXF.xxf_android:libs:5.2.2.1-SNAPSHOT'
    
    Application 与Activity 管理

    提供以下[直接访问]的内敛函数,其他组件扩展 400个函数 参考lib_ktx

    val applicationContext: Application
    
    val application: Application
    
    val activityList: List<Activity> 
    
    val topActivity: Activity
    
    val topActivityOrNull: Activity?
    
    val topFragmentActivityOrNull: FragmentActivity? 
    
    val topActivityOrApplication: Context
    
    
    http请求

    1. http接口interface声明(与retrofit十分类似) 全部采用注解式,灵活插拔,无client概念

    /**
    * 提供基础路由
    */
    @BaseUrl("http://api.map.baidu.com/")
    
    /**
    * 提供缓存目录设置
    */
    @RxHttpCacheProvider(DefaultRxHttpCacheDirectoryProvider.class)
    /**
    * 声明拦截器
    */
    @Interceptor({MyLoggerInterceptor.class, MyLoggerInterceptor2.class})
    
    /**
    * 声明rxJava拦截器
    */
    @RxJavaInterceptor(DefaultCallAdapter.class)
    public interface LoginApiService {
    
       /**
        * 声明接口 跟retrofit一致
        *
        * @return
        */
       @GET("telematics/v3/weather?location=%E5%98%89%E5%85%B4&output=json&ak=5slgyqGDENN7Sy7pw29IUvrZ")
       Observable<JsonObject> getCity();
    
       /**
        * 在retrofit上面扩展了 @Cache 设置缓存类型
        *
        * @param cacheType
        * @return
        */
       @GET("telematics/v3/weather?location=%E5%98%89%E5%85%B4&output=json&ak=5slgyqGDENN7Sy7pw29IUvrZ")
       Observable<JsonObject> getCity(@Cache CacheType cacheType);
    
       /**
        * 缓存5s
        * 添加在方法上     @Headers("cache:5000")
        *
        * @param cacheType
        * @return
        */
       @GET("telematics/v3/weather?location=%E5%98%89%E5%85%B4&output=json&ak=5slgyqGDENN7Sy7pw29IUvrZ")
       @Headers("cache:5000")
       Observable<JsonObject> getCity2(@Cache CacheType cacheType);
    
       /**
        * 缓存
        * 添加在参数上 @Header("cache") long time
        *
        * @param cacheType
        * @return
        */
       @GET("telematics/v3/weather?location=%E5%98%89%E5%85%B4&output=json&ak=5slgyqGDENN7Sy7pw29IUvrZ")
       Observable<JsonObject> getCity3(@Header("cache") long time, @Cache CacheType cacheType);
    
    
       @GET("telematics/v3/weather?location=%E5%98%89%E5%85%B4&output=json&ak=5slgyqGDENN7Sy7pw29IUvrZ")
       @RxHttpCache(CacheType.onlyCache)
       Observable<JsonObject> getCityOnlyCache();
    
    }
    

    缓存模式

    public enum CacheType {
       /**
        * 先从本地缓存拿取,然后从服务器拿取,可能会onNext两次,如果本地没有缓存 最少执行oNext一次
        */
       firstCache,
       /**
        * 先从服务器获取,没有网络 读取本地缓存
        */
       firstRemote,
       /**
        * 只从服务器拿取
        */
       onlyRemote,
       /**
        * 只从本地缓存中拿取,没有缓存 执行逻辑同Observable.empty()
        */
       onlyCache,
    
       /**
        * 如果本地存在就返回本地的,否则返回网络的数据
        */
       ifCache,
    
       /**
        * 读取上次的缓存,上次没有缓存就返回网络的数据,然后同步缓存;
        * 上次有缓存,也会同步网络数据 但不会onNext
        */
       lastCache;
    }
    
    1. api 请求方式,并绑定loading对话框

           BackupApiService::class.java.apiService()
                    .backupUpConfigQuestionQuery()
                    .map(new ResponseDTOSimpleFunction<List<SecurityQuestionDTO>>())
                    .bindProgressHud(this))//绑定progress loadingdialog
                    .subscribe(new Consumer<List<SecurityQuestionDTO>>() {
                        @Override
                        public void accept(List<SecurityQuestionDTO> securityQuestionDTOS) throws Exception {
                         
                        }
                    });
    

    kotlin 方式

           BackupApiService::class.apiService()
           
           getApiService<BackupApiService>()
            
    

    拓展上传的文件类型
    支持7种标识文件的方式,注意一般的服务器都支持 不传filename在表单,这个取决于你的服务器
    也就是协议中的 Content-Disposition: form-data; name=”file” 与 Content-Disposition: form-data; name=”file”; filename=”1705161084857114.jpeg” 的区别
    或者我提供了很多拓展uri.toPart(“filename”),file.toPart(“filename”)…

    1. File
    2. ByteArray
    3. inputStream
    4. FileDescriptor
    5. ParcelFileDescriptor
    6. AssetFileDescriptor
    7. Uri
      如下demo

    @POST("api/rentalAreaPad/uploadFile")
    @Multipart
    fun uploadRentalAreaPadFile2(
    @Query("companyId") companyId: String,
    @Part("file") fileUri: Uri,
    ): Observable<BaseResultDTO<String>>
    
    RxJava生命周期管理

    在Activity,Fragment,DialogFragment中都可以使用RxJava管理生命周期,语法保持一致,如下:

        io.reactivex.Observable.interval(1, TimeUnit.SECONDS)
                      .bindLifecycle(GrContactsFragment.this))//绑定生命周期
                      .subscribe(new Consumer<Long>() {
                          @Override
                          public void accept(Long aLong) throws Exception {
                              LogUtils.AndroidD("--------->ex:" + aLong);
                          }
                      });
    
    
    权限

    权限请求使用Rx链式调用(内部使用ActivityResultLauncher 且使用方免注册)
    常规为了避免断链式调用,那么需要attach隐藏的fragment,而这里的实现为站位ActivityResultLauncher
    更节约内存,且解决了并行的问题,也能免注册调用

      //请求授权
        ``` 
      支持activity fragment LifecycleOwner 挂载对象访问   如果是在其他类对象中 可以访问全局内敛函数 topFragmentActivity?.requestPermissionsObservable
      requestPermission(Manifest.permission.CAMERA)
                                .subscribe(new Consumer<Boolean>() {
                                    @Override
                                    public void accept(Boolean aBoolean) throws Exception {
                                        ToastUtils.showToast(v.getContext(), "Manifest.permission.CAMERA:" + aBoolean);
                                    }
                                });
                                
      //获取是否授权                          
      ToastUtils.showToast(v.getContext(), "Manifest.permission.CAMERA:" + checkSelfPermissions(Manifest.permission.CAMERA));
     ```
    
    startActivityForResult

    Rx链式调用(内部使用ActivityResultLauncher 且使用方免注册)
    常规为了避免断链式调用,那么需要attach隐藏的fragment,而这里的实现为站位ActivityResultLauncher
    更节约内存,且解决了并行的问题,也能免注册调用

       支持activity fragment LifecycleOwner 挂载对象访问 如果是在其他类对象中 可以访问全局内敛函数 topFragmentActivity?.startActivityForResultObservable
       startActivityForResult(new Intent(MainActivity.this, TestActivity.class))
                                  .subscribe(new Consumer<ActivityResult>() {
                                      @Override
                                      public void accept(ActivityResult activityResult) throws Exception {
                                          ToastUtils.showToast(v.getContext(), "activityResult:reqcode:" + activityResult.getRequestCode() + ";resCode" + activityResult.getResultCode() + ";data:" + activityResult.getData().getStringExtra("data"));
    
                                      }
                                  });   
    
    事件通信框架

    以字符串作为通信的模型举例:
    
    //订阅消息
    String.javaClass.subscribeEvent()
    .subscribe {
    
                }
     //发送消息           
    "测试".postEvent();
            
     //其他模型       
      TestEvent::class.java.subscribeEvent()
                    .subscribe {
                System.out.println("=====>"+"收到"+it);
            }
      TestEvent().postEvent();      
    
    Uri 授权

    Uri 授权每个app都去注册 十分麻烦,这里采用自动注册FileProvider

    File.toAuthorizedUri
    
    Json安全

    更加安全的JsonTypeAdapter,应对若语言类的服务器开发工程师,比如 把int 返回双引号空,框架内部
    兼容了int,bool,long,double,float,number,bigDecimal等常用类型的安全性

    GsonBuilder()
        .registerTypeAdapterFactory(new SafeTypeAdapterFactory())
        .build()
    

    这里同时也推荐我的另外一款code-gen工具
    对gson提升10倍速度,比市面上的任何序列化工具都优秀,请参考gson_plugin

    效率提升

    1. 增加避免装箱拆箱的LongHashMap 比如SparseArray查询效率更快,相比hashmap 提升50%,以及LongHashSet等组件
    2. 增加MurmurHash 比jdk自带hash 更快 200%提升
    3. 增加city hash 对于大数据 hash 效率更高
    委托属性

    获取viewbinding 可以 使用 by viewBinding()加载

       private val binding by viewBinding(ActivitySettingBinding::bind);
    
    
    activity intent和fragment Fragment参数绑定 可以使用 by argumentBinding(“xxx”)

        private val withNfcId: String? by argumentBinding("withNfcId");//携带了NFC卡号
    
    SharedPreference 可以采用 by

    读写 key value 委托,内部具体用什么缓存 由IPreferencesOwner决定,十分方便扩展,可以扩展为MMKV,sqlite,file等等

    object PreferencesDemo : SharedPreferencesOwner {
    
        data class User(val name: String? = null)
    
        var name: String by preferencesBinding("key", "xxx")
    
        //可以监听
        var name2: String by preferencesBinding("key2", "xxx").observable { property, newValue ->
            println("=============>PrefsDemo3:$newValue")
        }
        var user: User by preferencesBinding("key3", User()).useGson()
    
        fun test() {
            println("=============>PrefsDemo:$name")
            name = randomUUIDString32;
            println("=============>PrefsDemo2:$name")
            name2 = randomUUIDString32;
            println("=============>PrefsDemo4:$name2")
    
            println("=============>PrefsDemoUserBefore:$user")
            user = User("张三 ${System.currentTimeMillis()}")
            println("=============>PrefsDemoUser:$user")
        }
    }
    
    inline fun <P : IPreferencesOwner, reified V> PrefsDelegate<P, out V>.useGson(): KeyValueDelegate<P, V> {
        return object : KeyValueDelegate<P, V>(this.key, this.default) {
            private val stringDelegate by lazyUnsafe {
                PrefsDelegate<P, String>(this.key, "", String::class);
            }
    
            override fun getValue(thisRef: P, property: KProperty<*>): V {
                val value = stringDelegate.getValue(thisRef, property)
                return if (value.isEmpty()) {
                    default
                } else {
                    Json.fromJson<V>(value) ?: default
                }
            }
    
            override fun setValue(thisRef: P, property: KProperty<*>, value: V) {
                stringDelegate.setValue(thisRef, property, Json.toJson(value));
            }
        }
    }
    
    自定义相册

        //需额外加依赖
        implementation 'com.NBXXF.xxf_android:lib_album:xxxx'
    

       AlbumLauncher.from(SampleActivity.this)
                            .choose(MimeType.ofImage(), false)
                            .countable(true)
                            .capture(true)
                            .maxSelectable(9)
                            .addFilter(new GifSizeFilter(320, 320, 5 * Filter.K * Filter.K))
                            .gridExpectedSize(
                                    getResources().getDimensionPixelSize(R.dimen.grid_expected_size))
                            .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
                            .thumbnailScale(0.85f)
                            .imageEngine(new GlideEngine())
                            .setOnSelectedListener((uriList, pathList) -> {
                                Log.e("onSelected", "onSelected: pathList=" + pathList);
                            })
                            .showSingleMediaType(true)
                            .originalEnable(true)
                            .maxOriginalSize(10)
                            .autoHideToolbarOnSingleTap(true)
                            .setOnCheckedListener(isChecked -> {
                                Log.e("isChecked", "onCheck: isChecked=" + isChecked);
                            })
                            .forResult()
                            .subscribe(new Consumer<AlbumResult>() {
                                @Override
                                public void accept(AlbumResult albumResult) throws Throwable {
                                    mAdapter.setData(albumResult.getUris(), albumResult.getPaths());
                                }
                            });
    

    自定义相机仿微信

        //需额外加依赖
        implementation 'com.NBXXF.xxf_android:lib_camera_wechat:xxxx'
    

     CameraLauncher.instance
                        //.openPreCamera()// 是否打开为前置摄像头
                        .allowPhoto(true)// 是否允许拍照 默认允许
                        .allowRecord(true)// 是否允许录像 默认允许
                        .setMaxRecordTime(3)//最长录像时间 秒
                        .forResult(this)
                        .subscribe {
                            if (it.isImage) {
                                text.text = "Image Path:\n${it.path}"
                            } else {
                                text.text = "Video Path:\n${it.path}"
                            }
                        }
    

    二维码生成

    QRCodeProviders.of(content)
                    .setOutputSize(new Size(width, height))
                    .setContentMargin(Integer.valueOf(margin))
                    .setContentColor(color_black)
                    .setBackgroundColor(color_white)
                    .setLogo(logoBitmap)
                    .setContentFillImg(blackBitmap)
                    .build();
    
    RecyclerView 分割线

    1. DividerDecorationFactory 工厂模式
    2. LinearItemDecoration 支持 水平 垂直 和格子
    圆角组件

    (app:radius=”8dp”,app:radius=”360dp” 为圆形 详细参考下面每个类的 类注释!!!)

    1. XXFRoundButton
    2. XXFRoundCheckedTextView
    3. XXFRoundEditText
    4. XXFRoundImageView
    5. XXFRoundTextView
    6. XXFRoundLayout
    7. XXFRoundLinearLayout
    8. XXFRoundRelativeLayout
    带渐变背景的组件

    (app:start_color app:end_color 详细参考下面每个类的 类注释!!!)

    1. XXFGradientCompatButton
    2. XXFGradientCompatCheckedTextView
    3. XXFGradientCompatEditText
    4. XXFGradientCompatImageView
    5. XXFGradientCompatTextView
    6. XXFGradientFrameLayout
    7. XXFGradientLinearLayout
    8. XXFGradientRelativeLayout
    设置宽高比例的组件

    (app:widthRatio app:heightRatio 详细参考下面每个类的 类注释!!!)

    1. XXFRationCompatButton
    2. XXFRationCompatCheckedTextView
    3. XXFRationCompatEditText
    4. XXFRationCompatImageView
    5. XXFRationCompatTextView
    6. XXFRationFrameLayout
    7. XXFRationLinearLayout
    8. XXFRationtRelativeLayout

    Visit original content creator repository

  • ncryptf-java

    ncryptf Java

    TravisCI License

    ncryptf logo

    A library for facilitating hashed based KDF signature authentication, and end-to-end encrypted communication with compatible API’s.

    Installing

    This library can be installed via Maven or Gradle via a JitPack checkout:

    Maven

    1. Add jitpack.io as a repository dependency in your pom.xml.
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
    1. Add this repository as a dependency. Be sure to replace LATEST_TAG_FROM_GITHUB appropriately.
    <dependency>
        <groupId>>com.ncryptf</groupId>
        <artifactId>ncryptf-java</artifactId>
        <version>LATEST_TAG_FROM_GITHUB</version>
    </dependency>

    Gradle

    1. Add jitpack.io to your root bundle.gradle file:
    allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }
    
    1. Add this repository as a dependency. Be sure to replace LATEST_TAG_FROM_GITHUB appropriately.
    dependencies {
        implementation 'com.github.charlesportwoodii:ncryptf-java:LATEST_TAG_FROM_GITHUB'
    }
    

    Testing

    ./gradlew clean install test
    

    Documentation

    Documentation is available on JitPack for the master branch.

    Javadoc documentation can be generated by running the following command:

    ./gradlew javadoc
    

    The HTML documentation will be placed in ./target/site/apidocs/index.html

    HMAC+HKDF Authentication

    HMAC+HKDF Authentication is an Authentication method that allows ensures the request is not tampered with in transit. This provides resiliance not only against network layer manipulation, but also man-in-the-middle attacks.

    At a high level, an HMAC signature is created based upon the raw request body, the HTTP method, the URI (with query parameters, if present), and the current date. In addition to ensuring the request cannot be manipulated in transit, it also ensures that the request is timeboxed, effectively preventing replay attacks.

    The library itself is made available by importing the following struct:

    Supporting API’s will return the following payload containing at minimum the following information.

    {
        "access_token": "7XF56VIP7ZQQOLGHM6MRIK56S2QS363ULNB5UKNFMJRQVYHQH7IA",
        "refresh_token": "MA2JX5FXWS57DHW4OIHHQDCJVGS3ZKKFCL7XM4GNOB567I6ER4LQ",
        "ikm": "bDEyECRvKKE8w81fX4hz/52cvHsFPMGeJ+a9fGaVvWM=",
        "signing": "7v/CdiGoEI7bcj7R2EyDPH5nrCd2+7rHYNACB+Kf2FMx405und2KenGjNpCBPv0jOiptfHJHiY3lldAQTGCdqw==",
        "expires_at": 1472678411
    }

    After extracting the elements, we can create signed request by doing the following:

    import com.ncryptf.Token;
    import com.ncryptf.Authorization;
    import com.ncryptf.exceptions.*;
    
    Token token = new Token(
        accessToken,
        refreshToken,
        ikm,
        signing,
        expiresAt
    );
    
    try {
        Authorization auth = new Authorization(
            httpMethod,
            uri,
            token,
            date,
            payload
        );
    
        String header = auth.getHeader();
    } catch (KeyDerivationException e) {
        // Handle errors
    }

    A trivial full example is shown as follows:

    import com.ncryptf.Token;
    import com.ncryptf.Authorization;
    import com.ncryptf.exceptions.*;
    import org.apache.commons.codec.binary.Base64;
    import java.time.Instant;
    import java.time.ZoneOffset;
    import java.time.ZonedDateTime;
    
    Token token = new Token(
        "7XF56VIP7ZQQOLGHM6MRIK56S2QS363ULNB5UKNFMJRQVYHQH7IA",
        "7XF56VIP7ZQQOLGHM6MRIK56S2QS363ULNB5UKNFMJRQVYHQH7IA",
        Base64.decodeBase64("bDEyECRvKKE8w81fX4hz/52cvHsFPMGeJ+a9fGaVvWM="),
        Base64.decodeBase64("7v/CdiGoEI7bcj7R2EyDPH5nrCd2+7rHYNACB+Kf2FMx405und2KenGjNpCBPv0jOiptfHJHiY3lldAQTGCdqw=="),
        ZonedDateTime.ofInstant(Instant.ofEpochSecond(1472678411), ZoneOffset.UTC)
    )
    
    ZonedDateTime date = ZonedDateTime.now(ZoneOffset.UTC);
    
    try {
        Authorization auth = new Authorization(
            "POST",
            "/api/v1/test",
            token,
            date,
            "{\"foo\":\"bar\"}"
        );
    
        String header = auth.getHeader();
    } catch (KeyDerivationException e) {
        // Handle errors
    }

    Note that the date property should be pore-offset when calling Authorization to prevent time skewing.

    The payload parameter should be a JSON serializable string.

    Version 2 HMAC Header

    The Version 2 HMAC header, for API’s that support it can be retrieved by calling:

    String header = auth.getHeader();

    Version 1 HMAC Header

    For API’s using version 1 of the HMAC header, call Authorization with the optional version parameter set to 1 for the 6th parameter.

    try {
        Authorization auth = new Authorization(
            httpMethod,
            uri,
            token,
            date,
            payload,
            1
        );
    
        String header = auth.getHeader();
    } catch (KeyDerivationException e) {
        // Handle errors
    }

    This string can be used in the Authorization Header

    Date Header

    The Version 1 HMAC header requires an additional X-Date header. The X-Date header can be retrieved by calling auth.getDateString()

    Encrypted Requests & Responses

    This library enables clients to establish and trusted encrypted session on top of a TLS layer, while simultaniously (and independently) providing the ability authenticate and identify a client via HMAC+HKDF style authentication.

    The rationale for this functionality includes but is not limited to:

    1. Necessity for extra layer of security
    2. Lack of trust in the network or TLS itself (see https://blog.cloudflare.com/incident-report-on-memory-leak-caused-by-cloudflare-parser-bug/)
    3. Need to ensure confidentiality of the Initial Key Material (IKM) provided by the server for HMAC+HKDF authentication
    4. Need to ensure confidentiality of user submitted credentials to the API for authentication

    The primary reason you may want to establish an encrypted session with the API itself is to ensure confidentiality of the IKM to prevent data leakages over untrusted networks to avoid information being exposed in a Cloudflare like incident (or any man-in-the-middle attack). Encrypted sessions enable you to utilize a service like Cloudflare should a memory leak occur again with confidence that the IKM and other secure data would not be exposed.

    To encrypt, decrypt, sign, and verify messages, you’ll need to be able to generate the appropriate keys. Internally, this library uses lazysodium-java to perform all necessary cryptography functions, though any libsodium implementation for Java would suffice.

    Encryption Keys

    Encryption uses a sodium crypto box. A keypair can be generated as follows when using lazy-sodium.

    import com.ncryptf.Utils;
    import com.ncryptf.Keypair;
    Keypair kp = Utils.generateKeypair();

    Signing Keys

    Encryption uses a sodium signature. A keypair for signing can be generated as follows using lazy-sodium:

    import com.ncryptf.Utils;
    import com.ncryptf.Keypair;
    Keypair kp = Utils.generateSigningKeypair();

    Encrypted Request Body

    Payloads can be encrypted as follows:

    import com.ncryptf.Request;
    import com.ncryptf.exceptions.*;
    import java.util.Base64;
    
    // Arbitrary string payload
    String payload = "{\"foo\":\"bar\"}";
    
    try {
        // 32 byte secret and public key. Extract from kp.get...().getAsBytes(), or another libsodium method
        Request request = new Request(secretKeyBytes, signingSecretKeyBytes /* token.signature */);
    
        // Cipher now contains the encryted data
        // Signature should be the signature private key previously agreed upon with the sender
        // If you're using a `Token` object, this should be the `.signature` property
        byte[] cipher = request.encrypt(payload, remotePublicKey);
    
        // Send as encrypted request body
        String b64Body = Base64.getEncoder().encode(cipher);
    
        // Do your http request here
    } catch (EncryptionFailedException e) {
        // Handle encryption errors here
    }

    Note that you need to have a pre-bootstrapped public key to encrypt data. For the v1 API, this is typically this is returned by /api/v1/server/otk.

    Decrypting Responses

    Responses from the server can be decrypted as follows:

    import com.ncryptf.Response;
    import com.ncryptf.exceptions.*;
    import java.util.Base64;
    
    try {
        // Grab the raw response from the server
        byte[] responseFromServer = Base64.getDecoder().decode("<HTTP-Response-Body>");
        Response response = new Response(clientSecretKey);
    
        String decrypted = response.decrypt(responseFromServer, remotePublicKey);
    } catch (InvalidChecksumException e) {
        // Checksum is not valid. Request body was tampered with
    } catch (InvalidSignatureException e) {
        // Signature verification failed
    } catch (DecryptionFailedException e) {
        // Decryption failed. This may be an issue with the provided nonce, or keypair being used
    }

    V2 Encrypted Payload

    Verison 2 works identical to the version 1 payload, with the exception that all components needed to decrypt the message are bundled within the payload itself, rather than broken out into separate headers. This alleviates developer concerns with needing to manage multiple headers.

    The version 2 payload is described as follows. Each component is concatanated together.

    Segment Length
    4 byte header DE259002 in binary format 4 BYTES
    Nonce 24 BYTES
    The public key associated to the private key 32 BYTES
    Encrypted Body X BYTES
    Signature Public Key 32 BYTES
    Signature or raw request body 64 BYTES
    Checksum of prior elements concatonated together 64 bytes
    Visit original content creator repository