Skip to content

Instantly share code, notes, and snippets.

@0xnu
Last active August 29, 2025 09:36
Show Gist options
  • Save 0xnu/529077809c6840d497c0047ad1ee8fae to your computer and use it in GitHub Desktop.
Save 0xnu/529077809c6840d497c0047ad1ee8fae to your computer and use it in GitHub Desktop.
Calculate Sales Tax with Global Tax API.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@name: cart_level_calculation.py
@author: Finbarrs Oketunji
@contact: f@finbarrs.eu
@time: Friday August 29 2025
@desc: Calculate Sales Tax for entire cart with Global Tax API.
@run: python3 cart_level_calculation.py
"""
import json
import requests
import asyncio
import aiohttp
from typing import Dict, List, Optional, Union
from concurrent.futures import ThreadPoolExecutor, as_completed
class GlobalSalesTaxCalculator:
def __init__(self, username: str, password: str) -> None:
self.username = username
self.password = password
self.api_key: Optional[str] = None
self.base_url = "https://globatax.com/v2"
def login(self) -> bool:
url = f"{self.base_url}/login"
payload = json.dumps({"username": self.username, "password": self.password})
headers = {"Content-Type": "application/json", "Accept": "application/json"}
response = requests.post(url, headers=headers, data=payload)
if response.status_code == 200:
self.api_key = response.json()["api_key"]
return True
else:
print(f"Login failed. Status Code: {response.status_code}")
print(f"Response: {response.text}")
return False
def calculate_sales_tax(self, tax_data: Dict[str, Union[str, int, float]]) -> Optional[Dict]:
"""Single item tax calculation - returns full response for debugging"""
if self.api_key is None:
print("Please login first.")
return None
url = f"{self.base_url}/calculate_taxes"
payload = json.dumps(tax_data)
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Cookie": f"api_key={self.api_key}",
}
response = requests.post(url, headers=headers, data=payload)
if response.status_code == 200:
return response.json()
else:
print(f"Failed to calculate sales tax. Status Code: {response.status_code}")
print(f"Response: {response.text}")
return None
def calculate_cart_tax_sequential(self, vendor_country: str, customer_country: str,
line_items: List[Dict], shipping_cost: float = 0) -> Dict:
"""
Calculate tax for entire cart using sequential API calls.
Distributes shipping cost proportionally across line items.
"""
if not line_items:
return {"error": "No line items provided"}
# Calculate total item value for shipping distribution
total_items_value = sum(item["item_amount"] for item in line_items)
results = []
total_tax = 0
total_cart_value = 0
for i, item in enumerate(line_items):
# Calculate proportional shipping for this item
if shipping_cost > 0 and total_items_value > 0:
item_shipping = (item["item_amount"] / total_items_value) * shipping_cost
else:
item_shipping = 0
tax_data = {
"vendor_country": vendor_country,
"customer_country": customer_country,
"service_type_code": item["service_type_code"],
"item_amount": item["item_amount"],
"shipping_cost": item_shipping
}
# Calculate tax for this item
tax_result = self.calculate_sales_tax(tax_data)
if tax_result:
item_result = {
"line_item_index": i,
"original_item": item,
"item_amount": item["item_amount"],
"shipping_portion": item_shipping,
"service_type_code": item["service_type_code"],
"tax_amount": tax_result.get("tax_amount", 0),
"tax_rate": tax_result.get("tax_rate", 0),
"full_response": tax_result
}
results.append(item_result)
total_tax += tax_result.get("tax_amount", 0)
total_cart_value += item["item_amount"]
else:
# Handle failed calculation
results.append({
"line_item_index": i,
"original_item": item,
"error": "Tax calculation failed"
})
return {
"success": True,
"line_item_results": results,
"summary": {
"total_items_value": total_cart_value,
"shipping_cost": shipping_cost,
"total_tax": total_tax,
"grand_total": total_cart_value + shipping_cost + total_tax,
"currency": self._determine_currency(vendor_country)
},
"api_calls_used": len(line_items)
}
def calculate_cart_tax_parallel(self, vendor_country: str, customer_country: str,
line_items: List[Dict], shipping_cost: float = 0,
max_workers: int = 5) -> Dict:
"""
Calculate cart tax using parallel processing to speed up multiple API calls.
"""
if not line_items:
return {"error": "No line items provided"}
total_items_value = sum(item["item_amount"] for item in line_items)
def calculate_item_tax(item_data):
i, item = item_data
# Calculate proportional shipping
if shipping_cost > 0 and total_items_value > 0:
item_shipping = (item["item_amount"] / total_items_value) * shipping_cost
else:
item_shipping = 0
tax_data = {
"vendor_country": vendor_country,
"customer_country": customer_country,
"service_type_code": item["service_type_code"],
"item_amount": item["item_amount"],
"shipping_cost": item_shipping
}
result = self.calculate_sales_tax(tax_data)
return (i, item, result, item_shipping)
results = []
total_tax = 0
# Use ThreadPoolExecutor for parallel API calls
with ThreadPoolExecutor(max_workers=max_workers) as executor:
# Submit all tasks
future_to_item = {
executor.submit(calculate_item_tax, (i, item)): (i, item)
for i, item in enumerate(line_items)
}
# Collect results as they complete
for future in as_completed(future_to_item):
try:
i, item, tax_result, item_shipping = future.result()
if tax_result:
item_result = {
"line_item_index": i,
"original_item": item,
"item_amount": item["item_amount"],
"shipping_portion": item_shipping,
"service_type_code": item["service_type_code"],
"tax_amount": tax_result.get("tax_amount", 0),
"tax_rate": tax_result.get("tax_rate", 0)
}
total_tax += tax_result.get("tax_amount", 0)
else:
item_result = {
"line_item_index": i,
"original_item": item,
"error": "Tax calculation failed"
}
results.append(item_result)
except Exception as e:
results.append({
"line_item_index": i,
"error": f"Exception during calculation: {str(e)}"
})
# Sort results by line item index
results.sort(key=lambda x: x["line_item_index"])
return {
"success": True,
"line_item_results": results,
"summary": {
"total_items_value": sum(item["item_amount"] for item in line_items),
"shipping_cost": shipping_cost,
"total_tax": total_tax,
"grand_total": sum(item["item_amount"] for item in line_items) + shipping_cost + total_tax,
"currency": self._determine_currency(vendor_country)
},
"api_calls_used": len(line_items),
"processing_method": "parallel"
}
def _determine_currency(self, vendor_country: str) -> str:
"""Determine currency based on vendor country"""
currency_map = {
"GBR": "GBP", "US": "USD", "USA": "USD",
"DE": "EUR", "FR": "EUR", "BE": "EUR", "NL": "EUR",
"CA": "CAD", "AU": "AUD"
}
return currency_map.get(vendor_country.upper(), "USD")
def main() -> None:
username = "enter_your_username_here"
password = "enter_your_password_here"
calculator = GlobalSalesTaxCalculator(username, password)
if calculator.login():
# Sample shopping cart
cart_items = [
{
"service_type_code": "TOS25871",
"item_amount": 250,
"product_name": "Premium Software License"
},
{
"service_type_code": "TOS25872",
"item_amount": 180,
"product_name": "Hardware Device"
},
{
"service_type_code": "TOS25871",
"item_amount": 95,
"product_name": "Support Package"
}
]
print("Calculating taxes for cart with parallel processing...")
# Use parallel processing for faster results
cart_tax_result = calculator.calculate_cart_tax_parallel(
vendor_country="GBR",
customer_country="BE",
line_items=cart_items,
shipping_cost=35,
max_workers=3 # Adjust based on API rate limits
)
if cart_tax_result.get("success"):
print("\n=== CART TAX CALCULATION RESULTS ===")
print(f"Total Items Value: £{cart_tax_result['summary']['total_items_value']}")
print(f"Shipping Cost: £{cart_tax_result['summary']['shipping_cost']}")
print(f"Total Tax: £{cart_tax_result['summary']['total_tax']}")
print(f"Grand Total: £{cart_tax_result['summary']['grand_total']}")
print(f"API Calls Used: {cart_tax_result['api_calls_used']}")
print("\n=== LINE ITEM BREAKDOWN ===")
for item in cart_tax_result["line_item_results"]:
if "error" not in item:
print(f"Item {item['line_item_index'] + 1}: {item['original_item'].get('product_name', 'Unknown')}")
print(f" Amount: £{item['item_amount']}")
print(f" Shipping Portion: £{item['shipping_portion']:.2f}")
print(f" Tax: £{item['tax_amount']}")
print(f" Rate: {item['tax_rate']}%")
else:
print(f"Item {item['line_item_index'] + 1}: ERROR - {item['error']}")
else:
print("Cart tax calculation failed")
print(json.dumps(cart_tax_result, indent=2))
if __name__ == "__main__":
main()
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Text.Json;
namespace GlobalSalesTaxCalculator
{
class GlobalSalesTaxCalculator
{
private string username;
private string password;
private string? apiKey;
public GlobalSalesTaxCalculator(string username, string password)
{
this.username = username;
this.password = password;
this.apiKey = null;
}
public bool Login()
{
string url = "https://globatax.com/v2/login";
var payload = new { username = this.username, password = this.password };
string jsonPayload = JsonSerializer.Serialize(payload);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = client.PostAsync(url, content).Result;
if (response.IsSuccessStatusCode)
{
var jsonResponse = response.Content.ReadAsStringAsync().Result;
var result = JsonSerializer.Deserialize<Dictionary<string, string>>(jsonResponse);
this.apiKey = result["api_key"];
return true;
}
else
{
Console.WriteLine($"Login failed. Status Code: {response.StatusCode}");
Console.WriteLine($"Response: {response.Content.ReadAsStringAsync().Result}");
return false;
}
}
}
public float? CalculateSalesTax(Dictionary<string, object> taxData)
{
if (this.apiKey == null)
{
Console.WriteLine("Please login first.");
return null;
}
string url = "https://globatax.com/v2/calculate_taxes";
string jsonPayload = JsonSerializer.Serialize(taxData);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Cookie", $"api_key={this.apiKey}");
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = client.PostAsync(url, content).Result;
if (response.IsSuccessStatusCode)
{
var jsonResponse = response.Content.ReadAsStringAsync().Result;
var result = JsonSerializer.Deserialize<Dictionary<string, float>>(jsonResponse);
return result["tax_amount"];
}
else
{
Console.WriteLine($"Failed to calculate sales tax. Status Code: {response.StatusCode}");
Console.WriteLine($"Response: {response.Content.ReadAsStringAsync().Result}");
return null;
}
}
}
}
class Program
{
static void Main()
{
string username = "enter_your_username";
string password = "enter_your_password";
var calculator = new GlobalSalesTaxCalculator(username, password);
if (calculator.Login())
{
var taxData = new Dictionary<string, object>
{
{ "vendor_country", "GBR" },
{ "customer_country", "BE" },
{ "service_type_code", "TOS25871" },
{ "item_amount", 250 },
{ "shipping_cost", 35 }
};
float? taxAmount = calculator.CalculateSalesTax(taxData);
if (taxAmount != null)
{
Console.WriteLine($"Estimated Sales Tax: {taxAmount}");
}
}
}
}
}
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@name: global_sales_tax.py
@author: Finbarrs Oketunji
@contact: f@finbarrs.eu
@time: Tuesday March 19 05:20:00 2024
@desc: Calculate Sales Tax with Global Tax API.
@run: python3 global_sales_tax.py
"""
import json
import requests
from typing import Dict, Optional
class GlobalSalesTaxCalculator:
def __init__(self, username: str, password: str) -> None:
self.username = username
self.password = password
self.api_key: Optional[str] = None
def login(self) -> bool:
url = "https://globatax.com/v2/login"
payload = json.dumps({"username": self.username, "password": self.password})
headers = {"Content-Type": "application/json", "Accept": "application/json"}
response = requests.post(url, headers=headers, data=payload)
if response.status_code == 200:
self.api_key = response.json()["api_key"]
return True
else:
print(f"Login failed. Status Code: {response.status_code}")
print(f"Response: {response.text}")
return False
def calculate_sales_tax(self, tax_data: Dict[str, str | int | float]) -> Optional[float]:
if self.api_key is None:
print("Please login first.")
return None
url = "https://globatax.com/v2/calculate_taxes"
payload = json.dumps(tax_data)
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Cookie": f"api_key={self.api_key}",
}
response = requests.post(url, headers=headers, data=payload)
if response.status_code == 200:
return response.json()["tax_amount"]
else:
print(f"Failed to calculate sales tax. Status Code: {response.status_code}")
print(f"Response: {response.text}")
return None
def main() -> None:
username = "enter_your_username"
password = "enter_your_password"
calculator = GlobalSalesTaxCalculator(username, password)
if calculator.login():
tax_data = {
"vendor_country": "GBR",
"customer_country": "BE",
"service_type_code": "TOS25871",
"item_amount": 250,
"shipping_cost": 35,
}
tax_amount = calculator.calculate_sales_tax(tax_data)
if tax_amount is not None:
print(f"Estimated Sales Tax: {tax_amount}")
if __name__ == "__main__":
main()
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.HashMap;
import java.util.Map;
class GlobalSalesTaxCalculator {
private String username;
private String password;
private String apiKey;
public GlobalSalesTaxCalculator(String username, String password) {
this.username = username;
this.password = password;
this.apiKey = null;
}
public boolean login() throws IOException, InterruptedException {
String url = "https://globatax.com/v2/login";
Map<String, String> loginData = new HashMap<>();
loginData.put("username", this.username);
loginData.put("password", this.password);
String payload = new ObjectMapper().writeValueAsString(loginData);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
Map<String, String> responseMap = new ObjectMapper().readValue(response.body(), Map.class);
this.apiKey = responseMap.get("api_key");
return true;
} else {
System.out.println("Login failed. Status Code: " + response.statusCode());
System.out.println("Response: " + response.body());
return false;
}
}
public Float calculateSalesTax(Map<String, Object> taxData) throws IOException, InterruptedException {
if (this.apiKey == null) {
System.out.println("Please login first.");
return null;
}
String url = "https://globatax.com/v2/calculate_taxes";
String payload = new ObjectMapper().writeValueAsString(taxData);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.header("Cookie", "api_key=" + this.apiKey)
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
Map<String, Float> responseMap = new ObjectMapper().readValue(response.body(), Map.class);
return responseMap.get("tax_amount");
} else {
System.out.println("Failed to calculate sales tax. Status Code: " + response.statusCode());
System.out.println("Response: " + response.body());
return null;
}
}
public static void main(String[] args) throws IOException, InterruptedException {
String username = "enter_your_username";
String password = "enter_your_password";
GlobalSalesTaxCalculator calculator = new GlobalSalesTaxCalculator(username, password);
if (calculator.login()) {
Map<String, Object> taxData = new HashMap<>();
taxData.put("vendor_country", "GBR");
taxData.put("customer_country", "BE");
taxData.put("service_type_code", "TOS25871");
taxData.put("item_amount", 250);
taxData.put("shipping_cost", 35);
Float taxAmount = calculator.calculateSalesTax(taxData);
if (taxAmount != null) {
System.out.println("Estimated Sales Tax: " + taxAmount);
}
}
}
}
<?php
declare(strict_types=1);
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
class GlobalSalesTaxCalculator
{
private string $username;
private string $password;
private ?string $api_key = null;
public function __construct(string $username, string $password)
{
$this->username = $username;
$this->password = $password;
}
public function login(): bool
{
$url = "https://globatax.com/v2/login";
$payload = json_encode(["username" => $this->username, "password" => $this->password]);
$headers = ["Content-Type" => "application/json", "Accept" => "application/json"];
try {
$client = new Client();
$response = $client->post($url, [
'headers' => $headers,
'body' => $payload
]);
if ($response->getStatusCode() === 200) {
$data = json_decode($response->getBody(), true);
$this->api_key = $data["api_key"];
return true;
} else {
echo "Login failed. Status Code: " . $response->getStatusCode() . "\n";
echo "Response: " . $response->getBody() . "\n";
return false;
}
} catch (RequestException $e) {
echo "Error: " . $e->getMessage() . "\n";
return false;
} catch (GuzzleException $e) {
echo "Error: " . $e->getMessage() . "\n";
return false;
}
}
public function calculate_sales_tax(array $tax_data): ?float
{
if ($this->api_key === null) {
echo "Please login first.\n";
return null;
}
$url = "https://globatax.com/v2/calculate_taxes";
$payload = json_encode($tax_data);
$headers = [
"Content-Type" => "application/json",
"Accept" => "application/json",
"Cookie" => "api_key={$this->api_key}"
];
try {
$client = new Client();
$response = $client->post($url, [
'headers' => $headers,
'body' => $payload
]);
if ($response->getStatusCode() === 200) {
$data = json_decode($response->getBody(), true);
return $data["tax_amount"];
} else {
echo "Failed to calculate sales tax. Status Code: " . $response->getStatusCode() . "\n";
echo "Response: " . $response->getBody() . "\n";
return null;
}
} catch (RequestException $e) {
echo "Error: " . $e->getMessage() . "\n";
return null;
} catch (GuzzleException $e) {
echo "Error: " . $e->getMessage() . "\n";
return null;
}
}
}
function main(): void
{
$username = "enter_your_username";
$password = "enter_your_password";
$calculator = new GlobalSalesTaxCalculator($username, $password);
if ($calculator->login()) {
$tax_data = [
"vendor_country" => "GBR",
"customer_country" => "BE",
"service_type_code" => "TOS25871",
"item_amount" => 250,
"shipping_cost" => 35,
];
$tax_amount = $calculator->calculate_sales_tax($tax_data);
if ($tax_amount !== null) {
echo "Estimated Sales Tax: " . $tax_amount . "\n";
}
}
}
main();
import axios from 'axios';
interface TaxData {
vendor_country: string;
customer_country: string;
service_type_code: string;
item_amount: number;
shipping_cost: number;
}
class GlobalSalesTaxCalculator {
private username: string;
private password: string;
private api_key: string | null = null;
constructor(username: string, password: string) {
this.username = username;
this.password = password;
}
async login(): Promise<boolean> {
const url = "https://globatax.com/v2/login";
const payload = { username: this.username, password: this.password };
const headers = { "Content-Type": "application/json", "Accept": "application/json" };
try {
const response = await axios.post(url, payload, { headers });
if (response.status === 200) {
this.api_key = response.data.api_key;
return true;
} else {
console.log(`Login failed. Status Code: ${response.status}`);
console.log(`Response: ${response.data}`);
return false;
}
} catch (error) {
console.error('Error:', error);
return false;
}
}
async calculate_sales_tax(tax_data: TaxData): Promise<number | null> {
if (this.api_key === null) {
console.log("Please login first.");
return null;
}
const url = "https://globatax.com/v2/calculate_taxes";
const payload = tax_data;
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"Cookie": `api_key=${this.api_key}`,
};
try {
const response = await axios.post(url, payload, { headers });
if (response.status === 200) {
return response.data.tax_amount;
} else {
console.log(`Failed to calculate sales tax. Status Code: ${response.status}`);
console.log(`Response: ${response.data}`);
return null;
}
} catch (error) {
console.error('Error:', error);
return null;
}
}
}
async function salestaxcalculator(): Promise<void> {
const username = "enter_your_username";
const password = "enter_your_password";
const calculator = new GlobalSalesTaxCalculator(username, password);
if (await calculator.login()) {
const tax_data: TaxData = {
vendor_country: "GBR",
customer_country: "BE",
service_type_code: "TOS25871",
item_amount: 250,
shipping_cost: 35,
};
const tax_amount = await calculator.calculate_sales_tax(tax_data);
if (tax_amount !== null) {
console.log(`Estimated Sales Tax: ${tax_amount}`);
}
}
}
if (require.main === module) {
salestaxcalculator();
}
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
type GlobalSalesTaxCalculator struct {
username string
password string
api_key string
}
func (c *GlobalSalesTaxCalculator) init(username string, password string) {
c.username = username
c.password = password
c.api_key = ""
}
func (c *GlobalSalesTaxCalculator) login() bool {
url := "https://globatax.com/v2/login"
payload := map[string]string{
"username": c.username,
"password": c.password,
}
jsonPayload, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonPayload))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Printf("Login failed. Error: %v\n", err)
return false
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
var response map[string]string
json.NewDecoder(resp.Body).Decode(&response)
c.api_key = response["api_key"]
return true
} else {
fmt.Printf("Login failed. Status Code: %d\n", resp.StatusCode)
fmt.Printf("Response: %s\n", resp.Body)
return false
}
}
func (c *GlobalSalesTaxCalculator) calculate_sales_tax(tax_data map[string]interface{}) float64 {
if c.api_key == "" {
fmt.Println("Please login first.")
return 0
}
url := "https://globatax.com/v2/calculate_taxes"
jsonPayload, _ := json.Marshal(tax_data)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonPayload))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
req.Header.Set("Cookie", fmt.Sprintf("api_key=%s", c.api_key))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Printf("Failed to calculate sales tax. Error: %v\n", err)
return 0
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
var response map[string]float64
json.NewDecoder(resp.Body).Decode(&response)
return response["tax_amount"]
} else {
fmt.Printf("Failed to calculate sales tax. Status Code: %d\n", resp.StatusCode)
fmt.Printf("Response: %s\n", resp.Body)
return 0
}
}
func main() {
username := "enter_your_username"
password := "enter_your_password"
var calculator GlobalSalesTaxCalculator
calculator.init(username, password)
if calculator.login() {
tax_data := map[string]interface{}{
"vendor_country": "GBR",
"customer_country": "BE",
"service_type_code": "TOS25871",
"item_amount": 250,
"shipping_cost": 35,
}
tax_amount := calculator.calculate_sales_tax(tax_data)
if tax_amount != 0 {
fmt.Printf("Estimated Sales Tax: %f\n", tax_amount)
}
}
}
@0xnu
Copy link
Author

0xnu commented Mar 19, 2024

Global Tax API

Automate sales tax compliance globally with our robust API, encompassing countries across all continents.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment