Giter Site home page Giter Site logo

nozzlegear / shopifysharp Goto Github PK

View Code? Open in Web Editor NEW
721.0 62.0 297.0 4.23 MB

ShopifySharp is a .NET library that helps developers easily authenticate with and manage Shopify stores.

Home Page: https://nozzlegear.com/shopify-development-handbook

License: MIT License

C# 97.84% F# 2.16%
shopify shopify-apps shopify-api dotnet dotnetcore dotnet-standard csharp fsharp

shopifysharp's Introduction

ShopifySharp: A .NET library for Shopify.

NuGet Build status license

ShopifySharp is a .NET library that enables you to authenticate and make API calls to Shopify. It's great for building custom Shopify Apps using C# and .NET. You can quickly and easily get up and running with Shopify using this library.

The Shopify Development Handbook

Learn how to build rock-solid Shopify apps with C# and ASP.NET

Building an app or integration for the Shopify store is hard work. There are a ton of things you need to keep in mind when stitching together all of the API calls, redirect URLs and app settings that you'll need to use.

You're going to be asking yourself all of these questions when you try to build an app for the Shopify store:

  • How can I charge my users when they use my app?
  • What in the world is an embedded app?
  • How should I be using Shopify's redirect URLs?
  • When should I be using a proxy page?
  • Am I dealing with webhooks the right way?
  • How can I let my user's actual customers interact with the app?
  • Can I add custom scripts to their website, and what can those scripts even do?
  • How the heck do I go about testing my app?

It's difficult to find blog posts or tutorials about building Shopify apps, and downright impossible if you're trying to build them with C# and ASP.NET. Shopify's own partner blog puts a huge focus on designing themes over building real, functional apps, and their API docs only go so far if you don't know what you're looking for.

The Shopify Development Handbook is a premium educational course that distills the experience of building Shopify applications and integrations into one concise and comprehensive course.

Click here to learn more about The Shopify Development Handbook, and get a FREE sample chapter on integrating a merchant's Shopify store with your app.

Installation

ShopifySharp is available on NuGet. You can install it with the dotnet command line:

Package Installation Documentation
ShopifySharp dotnet add package shopifysharp Click here.
ShopifySharp.Extensions.DependencyInjection dotnet add package shopifysharp.extensions.dependencyinjection Click here.

Shopify API version support

Shopify has begun versioning their API, meaning new features are locked behind newer versions of the API, and older versions of the API lose support and are eventually shut off. Due to the differences in ShopifySharp's SemVer versioning, and Shopify's date-based versioning, the following table should be consulted to determine which version of ShopifySharp supports which version of Shopify's API:

ShopifySharp version Shopify API version
4.x and below None, unsupported
5.0.0 - 5.5.0 2019-10
5.6.0 - 5.7.0 2020-07
5.8.0 - 5.10.0 2020-10
5.11.0 - 5.13.1 2021-07
5.14.0 - 5.15.0 2021-10
5.16.0 - 5.18.11 2022-04
5.19.0 - 5.19.1 2022-07
6.0.1 - 6.2.0 2023-01
6.3.0 - 6.12.2 2023-07
6.13.0 and above 2024-01

Note: ShopifySharp dropped support for .NET Framework 4.5 in version 5.14.0. More details in #438. The oldest version of .NET Framework we can support is whichever version is supported by .NET Standard 2.0.

Check the package's documentation for more information.

A work-in-progress

I first started working on ShopifySharp because .NET developers need a fully-featured library for interacting with Shopify and building Shopify apps, which didn't exist several years ago. My goal is to eventually reach 100% compatibility with the Shopify REST API, but, with that said, Shopify is constantly adding new APIs and altering old ones. I try my best to keep up with them, but I tend to prioritize the support of new APIs by how much I need them in my own Shopify apps.

Documentation

Click the link here to be brought to all of the documentation: ShopifySharp Wiki

Contributing to ShopifySharp

Check out our contribution guide for guidance on contributing new features, services, classes and bugfixes to ShopifySharp! The guide also contains details on how to set up and run ShopifySharp's test suite.

shopifysharp's People

Contributors

19bibo85 avatar ajayak avatar chaoticike avatar clement911 avatar cmgt avatar davron12 avatar dkershner6 avatar foxandrewj avatar github-actions[bot] avatar ishahrier avatar jason-cbd avatar judah4 avatar khungersumit avatar knopa avatar lasamuadib avatar lucasabond avatar matt-kaminski avatar mooglegiant avatar mrjono1 avatar mtsg-io avatar nozzlegear avatar paulthomasrowe avatar pylenius avatar rohanp1903 avatar seanonet avatar thomotron avatar vleontyev avatar yitzchok avatar zikoat avatar zxed avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

shopifysharp's Issues

Urgent: update to ShopifySharp v2.0.0 before June 1st, 2016

I'm going to open this issue and leave it open until June. This is a PSA for everybody using ShopifyAuthorizationService.IsAuthenticRequest on ShopifySharp v1.17.1 and below.

I strongly recommend updating to 2.0.0+ before June 1st, 2016. Shopify will completely remove the method for verifying authentic requests used in ShopifyAuthorizationService.IsAuthenticRequest on June 1st, 2016. After that date, this method will always return false in v1 builds.

See the section on 'MD5 Signature Validation' here for more details on the auth method used in v1.17.1 and below.

For those who've purchased The Shopify Development Handbook, I'm working on an update right now that will use ShopifySharp 2.x. You'll get it for free as soon as it's released in the next few weeks.

Remove the Humanizer dependency.

I had originally planned on using this package a lot more, but currently it's only being used for string formatting. C# 6.0's string interpolation, and even string.Format can handle that, which makes Humanizr completely useless.

  • Are there any enums still using Humanizr's Enum.ToString method?

Product Variant

Feature Request - Just checking to see if there is an ETA on adding Product Variant to the library. In particular, inventory management.

Cannot read any data after upgrade to 2

[ArgumentNullException: Array cannot be null.
Parameter name: bytes]
System.Text.Encoding.GetString(Byte[] bytes) +11445618
ShopifySharp.RequestEngine.CheckResponseExceptions(IRestResponse response) +242
ShopifySharp.d__4`1.MoveNext() +471

Code is:
var pages = await new ShopifyPageService(AuthState.ShopName, AuthState.AccessToken).ListAsync();

ShopifyAuthorizationService.BuildAuthorizationUrl should have a state parameter

The Shopify documentation (https://help.shopify.com/api/guides/authentication/oauth STEP 2) says that there is a parameter that can be added to the url so the app can generate a random number and verify that number later when the user returns with the access token. The BuildAuthorizationUrl method should have that parameter as an option so developers can use that security mechanism.

The documentation says:

To show the prompt, redirect the user to this URL:

https://{shop}.myshopify.com/admin/oauth/authorize?client_id={api_key}&scope={scopes}&redirect_uri={redirect_uri}&state={nonce}
...

{nonce} - a randomly selected value provided by your application, which is unique for each authorization request. During the OAuth callback phase, your application must check that this value matches the one you provided during authorization. This mechanism is important for the security of your application.

Plus APIs

Do you have access to a Plus account to test the Plus APIs against?

If not, the company I work for has a Plus account and is OK with me running tests against one of our development stores

Some notes on Order Risks

I have been working on a program that needs to check Order Risks, here are some notes from my partial implementation and questions to Shopify support:

I copied from another entity and service, I think it was Transaction. I made minimal modifications to add the different fields, and only implemented the get methods.

Order Risks contain an undocumented field, "merchant_message". In some cases, but not all, it is a duplicate of the "message" field. Support initially claimed the field was deprecated since it has been undocumented and is a duplicate of "message". When I found ones that were not duplicates and pointed it out to support, they reported that a Solutions Engineer confirmed that "message" is what Shopify sees in logs and "merchant_message" is what the merchant sees on the order. In a manual test, it ignored "merchant_message" and set both to the value I gave in "message". I was not able to get it to set a unique value for "merchant_message".

{ /* sent */
    "risk": {
        "message": "Test Med risk flag (message)",
        "merchant_message": "Test Med risk flag (merchant_message)",
        "recommendation": "investigate",
        "score": 0.5,
        "source": "External",
        "cause_cancel": false,
        "display": true
    }
}
{ /* received */
    "risk": {
        "id": <risk ID>
        "order_id": <order ID>
        "checkout_id": <checkout ID>
        "source": "External"
        "score": "0.5"
        "recommendation": "investigate"
        "display": true
        "cause_cancel": false
        "message": "Test Med risk flag (message)"
        "merchant_message": "Test Med risk flag (message)"
    }
}

Shipping address field needs to be nullable

The current data model requires a non nullable shipping address and it is possible that Shopify will send orders via webhooks that do not have shipping addresses. Typically these are orders that are submitted via a POS system and therefore there is no shipping address.

Document unsupported APIs

I think it would be useful to have a matrix that can reference which APIs are implemented or not.

IEnumerable vs List

Hi Joshua,

I think this is an issue/feature request unless I am doing something wrong. We are utilizing ShopifySharp extensively to update our store by syncing with an internal CMS. While writing the sync code, I am finding it cumbersome to work with the properties defined as IEnumerable. To manage and manipulate the property I invariably must do something like this:

var variants = remoteProduct.Variants.ToList();
currentVariant = variants.SingleOrDefault(x => x.Id == currentVariant.Id);
currentVariant.ImageId = image.Id;
remoteProduct.Variants = variants;

or

var images = remoteProduct.Images.ToList();
images.Add(newShopifyProductImage);
remoteProduct.Images = images;

Is there some inherent architectural reason you chose to go with IEnumerable? Does it make sense to possibly change them to List since at the end of the day we truly are simply manipulating simple JSON lists?

Thank you for your work on ShopifySharp so far!

Dan

Wrong Data Type

in the ShopifyProductFilterOptions class

    [JsonProperty("title")]
    public **long**?Title { get; set; } = null;
    [JsonProperty("vendor")]
    public **long**? Vendor { get; set; } = null;
    [JsonProperty("handle")]
    public **long**?Handle { get; set; } = null;
    [JsonProperty("product_type")]
    public **long**? ProductType { get; set; } = null;

these should be string type.
thanks

Support the [Online Access] and [Offline Access] oauth types

Shopify has announced a new type of access token that you can receive during the OAuth signup flow. For support, this lib will need to add a grants string array property when building an authorization URL. The only known value is per-user.

Leaving the grants array blank will return an access token that's identical to the one that was given before this change, though Shopify now calls this an "offline access" token. Specifying per-user in the grants array will give you the new "online access" token.

This page goes into the difference between the two tokens, but to summarize: the new "online access" token is like a temporary user password to the store. It's guaranteed to respect the user's permissions with the store, and it will expire after the user logs out of their Shopify account.

Throw a ShopifyRateLimitException when an API call hits the rate limit.

Discussed briefly in #62, I'd like to throw a specific rate limit exception when an API call hits Shopify's rate limit. Throwing a specific exception should help devs write cleaner code for handling the rate limit. This exception should inherit from the current ShopifyException class so that existing code can still catch the rate limit error.

try
{
  await orderService.DeleteAsync(orderId);
}
catch (ShopifyRateLimitException e)
{
  // You hit the Shopify API rate limit. Consider waiting for 10 seconds to 
  // clear your limit and then try again.
}
catch (ShopifyException e)
{
  // Something else went wrong that wasn't related to the API rate limit
}

SmartCollection Support

Hi All,

I'm just trying your library for the first time and I'm trying to get a list of CustomCollections and SmartColections. Is there any support for SmartCollections in the library or am I missing something?

Great work!

Cheers,
Dave

ShopifyOrder.NoteAttributes deserialized incorrectly

I tried to get NoteAttributes of ShopifyOrder. But "key" is always empty.
Shopify return NoteAttributes as:

"note_attributes": [
        {
            "name": "test",
            "value": "test"
        }
    ]

But library try to deserialize it into the IEnumerable<KeyValuePair<string, string>>.
KeyValuePair class has two properties Key and Value.
So only Value can be deserialized correctly.

Question concerning Updating products

I'm sure this is the wrong place to ask questions, but I couldn't find anywhere else.

I am wondering if its possible to update products with some minimum information without first retrieving the full product. For example, if I store the ProductId and I just want to update some conditional fields (almost all of them in a variant - the quantity and prices), is it possible to use your library to update that product without first reading the product (thus consuming 2 API calls).

If it is, can you please tell me how this can be done ?

Return Shopify API errors as KeyValuePairs instead of a JSON string

Right now, ShopifySharp returns any errors returned by the Shopify API as a JSON string. The errors are formatted like this:

{
    "errors": {
        "addresses.country": [
            "is not a valid country"
        ]
    }
}

It would be better if they were returned as a list of KeyValuePairs, which would allow the developer to list them out and sort them by their type.

Synchronous implementation of Shopify service methods

We've got some legacy framework here that ... long story short, I can't use async service method implementations. Task.Run() is not an option too.
I'm actually already using this library in production and already implemented synchronous methods for several services that I used (luckily RestSharp has synchronous calls) - it's basically removing async from signature and await in method body + ExecuteRequest() insted of ExecuteRequestAsync().
It's more of a question if you'll pull synchronous implementations if I'll create pull-request?
In my eyes, those still could be useful in legacy projects (like mine) and they're demand nothing in support, since they're basically duplicates of Async methods.
If yes - I'd wrote other services too, but I won't cover it with tests - reason is I don't know that testing framework you use, nor have time to learn it, sadly.

p.s. I remember other issues #69, #74 I said I'll fix and pull-request. I already fixed them in my production, just didn't have time to check everything and pull-request. Hope this weekend I'll have time to finally work a bit at home.

Provide a robust fix for unknown enums

Shopify's documentation comes nowhere close to documenting all available enum values, and this has really thrown a wrench in things. ShopifySharp tries to provide enums where applicable, but I've personally run into exceptions where Shopify returns an enum that isn't documented (therefore isn't in ShopifySharp) and fails to deserialize.

I feel that enums are still preferable to using plain strings, so we need a more robust solution that won't throw exceptions when trying to deserialize unknown enums.

Instead, the current plan is to make all of ShopifySharp's enums implement an "Unknown" value, and make them all use a custom converter that will deserialize unknown enum strings into the "Unknown" value. The ShopifySharp.Enums.ShopifyProcessingMethod is the first to do this.

Investigate supporting .NET Core projects.

I haven't had a chance to play around with .NET Core at all yet, but would like to migrate this project to it while still supporting .NET 4.X. I'm planning an update to The Shopify Development Handbook that will use ASP/.NET Core, so this is the perfect time to add support to ShopifySharp.

From my (currently limited) understanding, we'll need to remove the .csproj (:clap:) and replace it with a project.json file, then add net451 to the frameworks list. Not entirely sure yet, will investigate further.

No timetable for .NET Core support, but it's definitely planned.

Edit: We're currently in the middle of buying a house, which is why development on this issue and #62 has slowed. Rest assured, I'm fully committed to bringing .NET Core support to ShopifySharp!

Clean up the filter classes for .Count and .List commands.

The list/count filter classes have a bunch of duplication going on. List filter classes should instead be replaced by a generic ShopifyListFilter class that contains the following props:

public long SinceId

public int Page

public string Fields

It will inherit from a ShopifyCountFilter class, which contains the following props:

public DateTime CreatedAtMin

public DateTime CreatedAtMax

public DateTime UpdatedAtMin

public DateTime UpdatedAtMax

Almost every count and list command uses the properties in these two classes. The exceptions are those that either can't be filtered, or those that use all of these properties plus a couple of custom properties that are specific to their objects. Instead of doing something sensible, we've somehow (entirely my fault!) ended up with a bunch of different classes that repeat these common properties.

This would be a breaking change, though, so I'm marking it for Version 2.

Price (and other monetary properties) in models should not be type double

It's generally a very-very bad idea to save money (prices, etc) in double type. There's a decimal C# type just for mostly monetary purposes that won't give you calculation, casting, rounding, comparing mistakes that real types will give from time to time.
From what I see it's classes:

  • ShopifyCharge,
  • ShopifyProductVariant,
  • ShopifyCustomer,
  • ShopifyLineItem,
  • ShopifyOrder,
  • ShopifyRecurringCharge,
  • ShopifyShippingLine,
  • ShopifyTaxLine,
  • ShopifyTransaction,
  • ShopifyUsageCharge

In case you have other things to do I can fix it on this or next weekend and pull-request.

ShopifyScriptTag

ShopifyScriptTag does not have display_scope property.

Are you handling it internally. I couldn't create one.

Thanks

Requesting only specified fields

Is there a way to request only a subset of fields?
The API docs give this example:
GET /admin/orders.json?fields=created_at,id,name,total-price

Edit: After looking through the code, I found at least some have a fields parameter for the Get function, but not for the List function. In my case, I want to get basic info about all paid & unfulfilled orders, then get full info from specific orders on that list.

ShopifyListFilterOptions does not properly filter to specific order ids.

The ShopifyListFilterOptions class has broken (or been broken). When trying to count or list orders that are filtered to specific ids, ShopifyOrderService will send out a URL that looks like this:

https://my-shop.myshopify.com/admin/orders.json?Ids=System.Collections.Generic.List%601%5BSystem.Int64%5D&status=any&limit=250&page=1&fields=id%2Cnote

There are two problems here:

  1. Obviously, the list of ids isn't being serialized.
  2. The Ids parameter should be ids.

Update ShopifyAuthorizationService.IsValidRequest

Shopify has recently deprecated the MD5 + signature request validation method, replacing it instead with SHA256 + hmac. While MD5 + signature still works, it's only a matter of time before Shopify removes it completely.

ShopifyOrderStatus Enums need updating

ShopifyOrderStatus is missing some new enums, so I am unable to download unfulfilled orders. I can currently only receive all open orders for a given store

Error parsing fails when trying to authorize an OAuth code that has already been used.

The Shopify API returns an error format that isn't parsed correctly by ShopifySharp's RequestEngine. Instead of throwing an exception with the message "The authorization code was not found or was already used", it throws one with the generic "Response did not indicate success".

{"error":"invalid_request","error_description":"The authorization code was not found or was already used"}

Update Json.NET dependency to newer version

This ShopifySharp library (btw, it's good and helpful, thank you) currently references Newtonsoft.Json v7.0 . It's kind of an old version (at this point 9.0.1 is up) and makes it impossible to use newer version of Json.NET if you add ShopifySharp as NuGet package. Maybe you can update Json.NET version dependency in future releases.

Unable to Get Single MetaField

When using await service.GetAsync(metafieldId); the returned data is null. If I use await service.ListAsync(productId, "products"); it successfully returns all metafields related to that product. From that list, the MetaFieldId is the exact same as the one used in the GetAsync.

using ShopifySharp for Private Apps

Hi,

I have been struggling with finding a way to use this great library for private apps.

I always get the message "Invalid API key or access token (unrecognized login or wrong password)"

I'm pretty new to this library, so I wouldn't know if i'm doing it right or not. I ended up adding following method to class "ShopifyService":

    public void SetPrivateAppsAuth(string apiKey, string password)
    {
        _RestClient.Authenticator = new HttpBasicAuthenticator(apiKey, password);
    }

So, I can use it like:

        string myShopifyUrl = "https://your-store.myshopify.com";
        ShopifyProductService service = new ShopifyProductService(myShopifyUrl, null);
        service.SetPrivateAppsAuth(api_key, password);
        Task<IEnumerable<ShopifyProduct>> task = service.ListAsync();
        task.Wait();
        var products = task.Result;

Better support for POST and PUT requests.

ShopifySharp runs into an issue that many C# libs find themselves facing: non-nullable types and POST/PUT requests don't mesh that well. For example, take the following class:

public class MyObject
{
  public int Id { get; set; }
  public DateTime Created { get; set; }
  public double Price { get; set; }
  public bool Active { get; set; }
}

Suppose that we need to create a "MyObject" through the Shopify API, but the POST option expects just the Price property. We create a new "MyObject" like so:

var myObj = new MyObject() { Price = 123.00 };

And we send that object to our pretend API. However, because of the way C# works with non-nullable types, C# will send the following:

{ "id": 0, "created": "0001-01-01T00:00:00", "price": 123.00, "active": false }

That's not good. The API only wanted the price, but C# sent an empty Id and Created date, and a false Active flag too. This isn't a huge problem when using POST endpoints because Shopify will typically just ignore the extra stuff it isn't looking for.

The big problem is working with updates to objects through PUT requests. Suppose you now want to update just the Active property for an object that was already created. You create your object like so:

var myUpdatedObj = new MyObject() { Active = true };

But when you send it, C# serializes it into this:

{ "id": 0, "created": "0001-01-01T00:00:00", "price": 0, "active": true }

Now that's a big problem. Active got set to true, but the object's price was just set to 0 too. You probably didn't want to do that, but thanks to C#'s non-nullable types it happened anyway without any input from you. The only way to avoid doing this is to pull the object from the API first, then make changes to that object and send the whole object through the update.

That's far from ideal; now updating an object goes from one request to two, and wastes bandwidth too. For ShopifySharp 3.0, I'm looking into ways to prevent sending unnecessary information through POST and PUT requests. I have two solutions right now, but welcome any suggestions:

  1. Make all non-string properties nullable. Drawback is that you now have to check if a prop has a value when operating on an object (e.g. Created.Value.ToShortDateString() instead of Created.ToShortDateString()).
  2. Create separate classes for creating and updating an object, akin to the way Stripe.net handles create/update requests. Drawback is a lot of duplicated code, and making changes to one object will need to be reflected to its create/update objects too.

Blog API Support

Hi All,

Are there any plans to implement the Blog API?

Regards,
Dave.

Creating an unpublished product actually creates a published one

A bug in ShopifyProductService.CreateAsync will actually create a published product when trying to create an unpublished one. The problem is ShopifyProductCreateOptions are being added to the request body as separate properties, but should actually be added to the product property.

Currently looks like this:

{
    "product" : {
        ...
    },
    "published" : false
}

But should look like this:

{
    "product" : {
        ...
        "published" : false
    },
}

ShopifyProductFulfillmentService should be a string.

As reported in #10, ShopifyProductFulfillmentService should not be an enum. The Shopify API lets apps and developers create their own fulfillment services which could never be mapped to a hard-coded enum. While we could switch this over to a nullable enum, that's not very useful for developers trying to specify their own fulfillment service too.

To fix, this enum should be converted to a string.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.