0.9.50 • Published 1 month ago

react-native-payme-sdk v0.9.50

Weekly downloads
36
License
MIT
Repository
-
Last release
1 month ago

en

PayME SDK là bộ thư viện để các app có thể tương tác với PayME Platform. PayME SDK bao gồm các chức năng chính như sau:

  • Hệ thống đăng ký, đăng nhập, eKYC thông qua tài khoản ví PayME
  • Chức năng nạp rút chuyển tiền từ ví PayME.
  • Tích hợp các dịch vụ của PayME Platform.

Một số thuật ngữ

NameGiải thích
1appLà app mobile iOS/Android hoặc web sẽ tích hợp SDK vào để thực hiện chức năng thanh toán ví PayME.
2SDKLà bộ công cụ hỗ trợ tích hợp ví PayME vào hệ thống app.
3backendLà hệ thống tích hợp hỗ trợ cho app, server hoặc api hỗ trợ
4AESHàm mã hóa dữ liệu AES. Tham khảo
5RSAThuật toán mã hóa dữ liệu RSA.
6IBNInstant Payment Notification , dùng để thông báo giữa hệ thống backend của app và backend của PayME

Cài đặt

  • npm:
npm install react-native-payme-sdk
  • yarn:
yarn add react-native-payme-sdk

Android:

  • Update file build.gradle project
allprojects {
  repositories {
    google()
    jcenter()
    maven {
      url "https://plugins.gradle.org/m2/"
    }
    maven {
      url "https://jitpack.io"
    }
  }
}
  • Update file build.gradle Module
android {
  ...
  packagingOptions {
    exclude "META-INF/DEPENDENCIES"
    exclude "META-INF/LICENSE"
    exclude "META-INF/LICENSE.txt"
    exclude "META-INF/license.txt"
    exclude "META-INF/NOTICE"
    exclude "META-INF/NOTICE.txt"
    exclude "META-INF/notice.txt"
    exclude "META-INF/ASL2.0"
  }
}
  • Update file Android Manifest

Nếu App Tích hợp có sử dụng payCode = VNPAY thì cấu hình thêm urlscheme vào Activity nhận kết quả thanh toán để khi thanh toán xong bên ví VNPAY có thể tự động quay lại app tích hợp

<activity
  android:launchMode="singleTask"
  android:windowSoftInputMode="adjustResize"
  android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
  android:name=".MainActivity"
>
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
      android:scheme="apptest"
      android:host="payment.vnpay.result"
      tools:ignore="AppLinkUrlError"
    />
    </intent-filter>
  </activity>

Cấp quyền truy cập danh bạ khi dùng chức năng nạp điện thoại và chuyển tiền

  ...
    <uses-permission android:name="android.permission.READ_CONTACTS" />
  ...
  • MainActivity.java

⚠️⚠️⚠️ Đã xoá từ version 0.9.16 trở đi.

Vui lòng xoá 2 function này nếu đã cài đặt, nếu chưa thì xin bỏ qua bước này.

...
import android.content.Intent;
import com.facebook.react.ReactInstanceManager;
import com.reactnativepaymesdk.PaymeSdkModule;

public class MainActivity extends ReactActivity {
  ...
  @Override
  public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    PaymeSdkModule.Companion.onActivityResult(this,requestCode, resultCode, data);
  }

  @Override
  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    PaymeSdkModule.Companion.onRequestPermissionsResult(requestCode, permissions, grantResults);
  }
}

iOS:

cd ios && pod install
  • Podfile
target 'AppExample' do
  ...
  use_frameworks! :linkage => :static
  ...
end
  • Info.plist

Update file Info.plist của app với những key như sau (giá trị của string có thể thay đổi, đây là các message hiển thị khi yêu cầu người dùng cấp quyền tương ứng):

<key>NSCameraUsageDescription</key>
<string>Need to access your camera to capture a photo add and update profile picture.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Need to access your library to add a photo or video of kyc video</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Need to access your photo library to select a photo add and update profile picture</string>
<key>NSContactsUsageDescription</key>
<string>Need to access your contact</string>

Nếu không sử dụng tính năng danh bạ thì thêm vào cuối podfile

post_install do |installer|
   installer.pods_project.targets.each do |target|
       if target.name == 'PayMESDK'
           target.build_configurations.each do |config|
             config.build_settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] ||= '$(inherited)'
             config.build_settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] << 'IGNORE_CONTACT'
           end
       end
   end
end

Nếu như project iOS chưa cấu hình cho Swift thì có thể thêm file .swift rỗng tùy ý vào project từ XCode để tự động enable Bridging header.

  1. Mở XCode Project
  2. File -> New File -> Chọn .swift file -> Next -> Create -> Chọn Create Bridging Header img

Usage

Hệ thống PayME sẽ cung cấp cho app tích hợp các thông tin sau:

  • PublicKey : Dùng để mã hóa dữ liệu, app tích hợp cần truyền cho SDK để mã hóa.
  • AppToken : AppToken cấp riêng định danh cho mỗi app, cần truyền cho SDK để mã hóa
  • SecretKey : Dùng đã mã hóa và xác thực dữ liệu ở hệ thống backend cho app tích hợp.

Bên App sẽ cung cấp cho hệ thống PayME các thông tin sau:

  • AppPublicKey : Sẽ gửi qua hệ thống backend của PayME dùng để mã hóa.
  • AppPrivateKey: Sẽ truyền vào PayME SDK để thực hiện việc giải mã.

Chuẩn mã hóa: RSA-512bit.

Khởi tạo thư viện

Trước khi sử dụng PayME SDK cần gọi phương thức khởi tạo một lần duy nhất để khởi tạo SDK.

import payME, { ENV, LANGUAGES } from 'react-native-payme-sdk';

payME.init(
  appToken,
  publicKey,
  connectToken,
  privateKey,
  configColor,
  LANGUAGES.VIETNAMESE,
  ENV.SANDBOX
);

Constant

PropertyTypeDescription
ENV.SANDBOXenumMôi trường sandbox.
ENV.STAGINGenumMôi trường staging.
ENV.PRODUCTIONenumMôi trường production.

Parameters

PropertyTypeDescription
appTokenstringAppId cấp riêng định danh cho mỗi app, cần truyền cho SDK để mã hóa.
publicKeystringDùng để mã hóa dữ liệu, app tích hợp cần truyền cho SDK để mã hóa. Do hệ thống PayME cung cấp cho app tích hợp.
connectTokenstringapp cần truyền giá trị được cung cấp ở trên, xem cách tạo bên dưới.
privateKeystringapp cần truyền vào để giải mã dữ liệu. Bên app sẽ cung cấp cho hệ thống PayME.
configColorstring[]configColor : là tham số màu để có thể thay đổi màu sắc giao dịch ví PayME, kiểu dữ liệu là chuỗi với định dạng #rrggbb. Nếu như truyền 2 màu thì giao diện PayME sẽ gradient theo 2 màu truyền vào.

configColor : là tham số màu để có thể thay đổi màu sắc giao dịch ví PayME, kiểu dữ liệu là chuỗi với định dạng #rrggbb. Nếu như truyền 2 màu thì giao diện PayME sẽ gradient theo 2 màu truyền vào.

img

Cách tạo connectToken:

connectToken cần để truyền gọi api từ tới PayME và sẽ được tạo từ hệ thống backend của app tích hợp. Cấu trúc như sau:

  • Nodejs Example
import crypto from 'crypto';

const data = {
  timestamp: '2021-01-20T06:53:07.621Z',
  userId: 'ABC',
  phone: '0909998877',
};

const algorithm = `aes-256-cbc`;
const ivbyte = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
const iv = Buffer.from(ivbyte);

const cipher = crypto.createCipheriv(algorithm, secretKey, iv);

const encrypted = cipher.update(JSON.stringify(data), 'utf8', 'base64');

const connectToken = encrypted + cipher.final('base64');
  • React native Example
import forge from 'node-forge';

function encryptAES(text, secretKey) {
  const ivbyte = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  const cipher = forge.cipher.createCipher('AES-CBC', secretKey);
  cipher.start({ iv: ivbyte });
  cipher.update(forge.util.createBuffer(text, 'utf8'));
  cipher.finish();
  return forge.util.encode64(cipher.output.getBytes());
}

const data = {
  timestamp: '2021-01-20T06:53:07.621Z',
  userId: 'abc',
  phone: '0123456789',
};

const connectToken = encryptAES(JSON.stringify(data), appSecretkey);

Tạo connectToken bao gồm thông tin KYC (Dành cho các đối tác có hệ thống KYC riêng)

const data = {
  timestamp: '2021-01-20T06:53:07.621Z',
  userId: 'abc',
  phone: '0123456789',
  kycInfo: {
    fullname: 'Nguyễn Văn A',
    gender: 'MALE',
    birthday: '1995-01-20T06:53:07.621Z',
    address: '15 Nguyễn cơ thạch',
    identifyType: 'CMND',
    identifyNumber: '142744332',
    issuedAt: '2013-01-20T06:53:07.621Z',
    placeOfIssue: 'Hồ Chí Minh',
    video:
      'https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_480_1_5MG.mp4',
    face: 'https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__480.jpg',
    image: {
      front:
        'https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__480.jpg',
      back:
        'https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__480.jpg',
    },
  },
};

const connectToken = encryptAES(JSON.stringify(data), appSecretkey);
Tham sốBắt buộcGiải thích
timestampYesThời gian tạo ra connectToken theo định dạng iSO 8601 , Dùng để xác định thời gian timeout của connectToken. Ví dụ 2021-01-20T06:53:07.621Z
userIdYeslà giá trị cố định duy nhất tương ứng với mỗi tài khoản khách hàng ở dịch vụ, thường giá trị này do server hệ thống được tích hợp cấp cho PayME SDK
phoneNoSố điện thoại của hệ thống tích hợp

Trong đó AES là hàm mã hóa theo thuật toán AES. Tùy vào ngôn ngữ ở server mà bên hệ thống dùng thư viện tương ứng. Xem thêm tại đây https://en.wikipedia.org/wiki/Advanced_Encryption_Standard

Tham số KycInfo

Tham sốBắt buộcGiải thích
fullnameYesHọ tên
genderYesGiới tính ( MALE/FEMALE)
addressYesĐịa chỉ
identifyTypeYesLoại giấy tờ (CMND/CCCD)
identifyNumberYesSố giấy tờ
issuedAtYesNgày đăng ký
placeOfIssueYesNơi cấp
videoNođường dẫn tới video
faceNođường dẫn tới ảnh chụp khuôn mặt
frontNođường dẫn tới ảnh mặt trước giấy tờ
backNođường dẫn tới ảnh mặt sau giấy tờ

Mã lỗi của PayME SDK

Hằng sốMã lỗiGiải thích
EXPIRED401token hết hạn sử dụng
DEACTIVATED_ACCOUNT405Tài khoản đã bị vô hiệu hoá
NETWORK-1Kết nối mạng bị sự cố
SYSTEM-2Lỗi hệ thống
LIMIT-3Lỗi số dư không đủ để thực hiện giao dịch
ACCOUNT_NOT_ACTIVATED-4Lỗi tài khoản chưa kích hoạt
ACCOUNT_NOT_KYC-5Lỗi tài khoản chưa định danh
PAYMENT_ERROR-6Thanh toán thất bại
ERROR_KEY_ENCODE-7Lỗi mã hóa/giải mã dữ liệu
USER_CANCELLED-8Người dùng thao tác hủy
ACCOUNT_NOT_LOGIN-9Lỗi chưa đăng nhập tài khoản
BALANCE_ERROR-10Lỗi khi thanh toán bằng ví PayME mà số dư trong ví không đủ
PAYMENT_PENDING-11Thanh toán đang chờ xử lý
ACCOUNT_ERROR-12Lỗi tài khoản bị khóa

Các chức năng của PayME SDK

login()

Có 2 trường hợp

  • Dùng để login lần đầu tiên ngay sau khi khởi tạo PayME.
  • Dùng khi accessToken hết hạn, khi gọi hàm của SDK mà trả về mã lỗi ERROR_CODE.EXPIRED hoặc ERROR_CODE.DEACTIVATED_ACCOUNT, lúc này app cần gọi login lại để lấy accessToken dùng cho các chức năng khác.

Sau khi gọi login() thành công rồi thì mới gọi các chức năng khác của SDK ( openWallet, pay, ... )

payME.login(
  onSuccess: (response: any) => {
    if (response.accountStatus === AccountStatus.NOT_ACTIVATED) {
      // Tài khoản chưa kích hoạt
      // gọi fun openWallet() để kích hoạt tài khoản
    }
    if (response.accountStatus === AccountStatus.NOT_KYC) {
      // Tài khoản chưa định danh
      // gọi fun openKYC() để định danh tài khoản
    }
    if (response.accountStatus === AccountStatus.KYC_REVIEW) {
      // Tài khoản đã gửi thông tin định danh, đang chờ duyệt
    }
    if (response.accountStatus === AccountStatus.KYC_REJECTED) {
      // Yêu cầu định danh bị từ chối
			// gọi fun openKYC() để định danh tài khoản
    }
    if (response.accountStatus === AccountStatus.KYC_APPROVED) {
      // Tài khoản đã định danh
    }
  },
  onError: (error: any) => void,
);

getAccountInfo()

App có thể dùng thuộc tính này sau khi khởi tạo SDK để biết được trạng thái liên kết tới ví PayME.

payME.getAccountInfo(
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);

openKYC()

Hàm này được gọi khi từ app tích hợp khi muốn mở modal định danh tài khoản ( yêu cầu tài khoản phải chưa định danh).

payME.openKYC(
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);

openWallet() - Mở UI chức năng PayME tổng hợp

Hàm này được gọi khi từ app tích hợp khi muốn gọi 1 chức năng PayME bằng cách truyền vào tham số Action như trên.

payME.openWallet(
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);

Tham số

Tham sốBắt buộcGiải thích
onSuccessYesDùng để bắt callback khi thực hiện giao dịch thành công từ PayME SDK
onErrorYesDùng để bắt callback khi có lỗi xảy ra trong quá trình gọi PayME SDK

openHistory() - Mở UI chức năng lịch sử giao dịch

payME.openHistory(
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);

Tham số

Tham sốBắt buộcGiải thích
onSuccessYesDùng để bắt callback khi thao tác thành công từ PayME SDK
onErrorYesDùng để bắt callback khi có lỗi xảy ra trong quá trình gọi PayME SDK

deposit() - Nạp tiền

payME.deposit(
  (amount: Number),
  (closeWhenDone: Boolean),
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);

Hàm này có ý nghĩa giống như khi gọi openWallet với action Action.Deposit.

withdraw() - Rút tiền

payME.withdraw(
  (amount: Number),
  (closeWhenDone: Boolean),
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);

Hàm này có ý nghĩa giống như khi gọi openWallet với action Action.Withdraw.

transfer() - Chuyển tiền

payME.transfer(
  (amount: Number),
  (description: String),
  (closeWhenDone: Boolean),
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);
Tham sốBắt buộcGiải thích
amountYesDùng trong trường hợp action là Deposit/Withdraw thì truyền vào số tiền
descriptionYesNội dung chuyển tiền
closeWhenDoneYestrue: Đóng SDK khi hoàn tất giao dịch
onSuccessYesDùng để bắt callback khi thực hiện giao dịch thành công từ PayME SDK
onErrorYesDùng để bắt callback khi có lỗi xảy ra trong quá trình gọi PayME SDK

scanQR() - Mở chức năng quét mã QR để thanh toán

payME.scanQR(
  (payCode: String),
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);
Tham sốBắt buộcGiải thích
payCodeYesDanh sách phương thức thanh toán

Định dạng qr :

const qrString =
  '{$type}|${storeId}|${action}|${amount}|${note}|${orderId}|${userName}';

Ví dụ :

const qrString =
  'OPENEWALLET|54938607|PAYMENT|20000|Chuyentien|2445562323|taikhoan';
  • action: loại giao dịch ( 'PAYMENT' => thanh toán)
  • amount: số tiền thanh toán
  • note: Mô tả giao dịch từ phía đối tác
  • orderId: mã giao dịch của đối tác, cần duy nhất trên mỗi giao dịch. Tối đa 22 kí tự.
  • storeId: ID của store phía công thanh toán thực hiên giao dịch thanh toán
  • userName: Tên tài khoản
  • type: OPENEWALLET

payQRCode() - thanh toán mã QR code

payME.payQRCode(
  (qr: String),
  (payCode: String),
  (isShowResultUI: Boolean),
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);
Tham sốBắt buộcGiải thích
qrYesMã QR để thanh toán (Định dạng QR như hàm scanQR)
payCodeYesDanh sách phương thức thanh toán
isShowResultUIYesOption hiển thị UI kết quả giao dịch

getSupportedServices()

App có thể dùng thuộc tính này sau khi khởi tạo SDK để biết danh sách các dịch vụ mà PayME đang cung cấp

payME.getSupportedServices(
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);

openService()

Hàm này được gọi khi từ app tích hợp khi muốn gọi 1 dịch vụ mà PayME cũng cấp bằng cách truyền vào tham số service như trên

payME.openService(
  (service: Object),
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);

pay() - Thanh toán

Hàm này được dùng khi app cần thanh toán 1 khoản tiền từ ví PayME đã được kích hoạt.

payME.pay(
      amount: Number,
      note: String,
      orderId: String,
      storeId: Number?,
      userName: String?,
      extractData: String,
      true,
      payCode: String,
      onSuccess: (response: any) => void,
      onError: (error: any) => void,
);
Tham sốBắt buộcGiải thích
amountYesSố tiền cần thanh toán bên app truyền qua cho SDK.
noteNoMô tả giao dịch từ phía đối tác.
orderIdYesMã giao dịch của đối tác, cần duy nhất trên mỗi giao dịch. Tối đa 22 kí tự.
storeIdNoID của store phía công thanh toán thực hiên giao dịch thanh toán.
userNameNoTên tài khoản.
extractDataNoThông tin bổ sung (extraData) là một nội dung được định nghĩa theo dạng chuỗi, chứa thông tin bổ sung của một giao dịch mà đối tác muốn nhận về khi hoàn tất một giao dịch với PAYME. Nếu Merchant ko cần IPN thêm data custom của mình có thể bỏ qua.
isShowResultUIYesOption hiển thị UI kết quả thanh toán.
payCodeYesDanh sách phương thức thanh toán
onSuccessYesDùng để bắt callback khi thực hiện giao dịch thành công từ PayME SDK
onErrorYesDùng để bắt callback khi có lỗi xảy ra trong quá trình gọi PayME SDK

Trong trường hợp app tích hợp cần lấy số dư để tự hiển thị lên UI trên app thì có thể dùng hàm, hàm này không hiển thị UI của PayME SDK.

  • Khi thanh toán bằng ví PayME thì yêu cầu tài khoản đã kích hoạt, định danh và số dư trong ví phải lớn hơn số tiền thanh toán
  • Thông tin tài khoản lấy qua hàm getAccountInfo()
  • Thông tin số dư lấy qua hàm getWalletInfo()

getRemainingQuota() - Lấy hạn mức giao dịch thanh toán

⚠️ Từ version 0.9.45

payME.getRemainingQuota(
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);

getWalletInfo() - Lấy các thông tin của ví

payME.getWalletInfo(
  (onSuccess: (response: any) => void),
  (onError: (error: any) => void)
);
  • Trong trường hợp lỗi thì hàm sẽ trả về message mỗi tại hàm onError , khi đó app có thể hiển thị balance là 0.
  • Trong trường hợp thành công SDK trả về thông tin như sau:
{
  "Wallet": {
    "balance": 111,
    "detail": {
      "cash": 1,
      "lockCash": 2
    }
  }
}

balance: App tích hợp có thể sử dụng giá trị trong key balance để hiển thị, các field khác hiện tại chưa dùng.

detail.cash: Tiền có thể dùng.

detail.lockCash: Tiền bị lock.

close() - Đóng UI

Hàm này được dùng để app tích hợp đóng lại UI của SDK khi đang payment hoặc openWallet

payME.close();

setLanguage()

Chuyển đổi ngôn ngữ của sdk

payME.setLanguage((language: LANGUAGES));

Ngôn ngữ hỗ trợ: VIETNAMESE, ENGLISH

Ví dụ :

payME.setLanguage(LANGUAGES.VIETNAMESE);

Danh sách phương thức thanh toán

payCodePhương thức thanh toán
PAYMEThanh toán ví PayME
ATMThanh toán thẻ ATM Nội địa
MANUAL_BANKThanh toán chuyển khoản ngân hàng
CREDITThanh toán thẻ tín dụng
VIET_QRThanh toán VietQR

Ghi chú

Làm việc với use_framework!

License

Copyright 2020 @ PayME

0.9.50

1 month ago

0.9.48

8 months ago

0.9.49

8 months ago

0.9.47

1 year ago

0.9.45

2 years ago

0.9.46

1 year ago

0.9.42

2 years ago

0.9.43

2 years ago

0.9.44

2 years ago

0.9.41

2 years ago

0.9.40

2 years ago

0.9.39

2 years ago

0.9.34

2 years ago

0.9.35

2 years ago

0.9.36

2 years ago

0.9.37

2 years ago

0.9.30

2 years ago

0.9.31

2 years ago

0.9.33

2 years ago

0.9.38

2 years ago

0.9.27

2 years ago

0.9.28

2 years ago

0.9.29

2 years ago

0.9.23

2 years ago

0.9.24

2 years ago

0.9.25

2 years ago

0.9.26

2 years ago

0.9.22

3 years ago

0.9.21

3 years ago

0.9.20

3 years ago

0.9.16

3 years ago

0.9.17

3 years ago

0.9.18

3 years ago

0.9.19

3 years ago

0.9.15

3 years ago

0.9.14

3 years ago

0.9.13

3 years ago

0.9.12

3 years ago

0.9.11

3 years ago

0.9.10

3 years ago

0.9.9

3 years ago

0.9.8

3 years ago

0.9.7

3 years ago

0.9.6

3 years ago

0.9.5

3 years ago

0.9.4

3 years ago

0.9.2

3 years ago

0.9.3

3 years ago

0.9.0

3 years ago

0.9.1

3 years ago

0.3.0

3 years ago

0.2.21

3 years ago

0.2.20

3 years ago

0.2.19

3 years ago

0.2.18

3 years ago

0.2.17

3 years ago

0.2.16

3 years ago

0.2.15

3 years ago

0.2.14

3 years ago

0.2.13

3 years ago

0.2.12

3 years ago

0.2.11

3 years ago

0.2.10

3 years ago

0.2.7

3 years ago

0.2.6

3 years ago

0.2.9

3 years ago

0.2.8

3 years ago

0.2.5

3 years ago

0.2.4

3 years ago

0.1.52

3 years ago

0.1.53

3 years ago

0.1.54

3 years ago

0.1.55

3 years ago

0.1.56

3 years ago

0.1.50

3 years ago

0.1.51

3 years ago

0.1.49

3 years ago

0.2.1

3 years ago

0.2.0

3 years ago

0.2.3

3 years ago

0.2.2

3 years ago

0.1.48

3 years ago

0.1.46

3 years ago

0.1.47

3 years ago

0.1.45

3 years ago

0.1.44

3 years ago

0.1.43

3 years ago

0.1.42

3 years ago

0.1.41

3 years ago

0.1.40

3 years ago

0.1.39

3 years ago

0.1.38

3 years ago

0.1.37

3 years ago

0.1.35

3 years ago

0.1.36

3 years ago

0.1.33

3 years ago

0.1.34

3 years ago

0.1.32

3 years ago

0.1.31

3 years ago

0.1.30

3 years ago

0.1.29

3 years ago

0.1.28

3 years ago

0.1.27

3 years ago

0.1.26

3 years ago

0.1.25

3 years ago

0.1.24

3 years ago

0.1.23

3 years ago

0.1.20

3 years ago

0.1.21

3 years ago

0.1.19

3 years ago

0.1.18

3 years ago

0.1.17

3 years ago

0.1.16

3 years ago

0.1.14

3 years ago

0.1.15

3 years ago

0.1.12

3 years ago

0.1.10

3 years ago

0.1.11

3 years ago

0.1.9

3 years ago

0.1.8

3 years ago

0.1.7

4 years ago

0.1.6

4 years ago

0.1.5

4 years ago

0.1.4

4 years ago

0.1.3

4 years ago

0.1.2

4 years ago

0.1.1

4 years ago

0.1.0

4 years ago