Coder Social home page Coder Social logo

modernuo / modernuo Goto Github PK

View Code? Open in Web Editor NEW
228.0 28.0 139.0 35.93 MB

Ultima Online Server Emulator for the modern era!

Home Page: https://www.modernuo.com

License: GNU General Public License v3.0

C# 99.86% Shell 0.01% Batchfile 0.01% HTML 0.12%
ultima-online uo csharp dotnet dotnet-core csharp-core emulator server mmorpg runuo

modernuo's Introduction

ModernUO Discord Subreddit subscribers Twitter Follow

Ultima Online Server Emulator for the modern era!

GitHub license GitHub stars GitHub issues
GitHub build Azure Pipelines build

Requirements

Supported Operating Systems

Windows 10/11/2019/2022 MacOS 11+ Debian 11+ Ubuntu 20+ LTS
Alpine 3.18+ Fedora 37+ RedHat 7/8 CentOS 7/8/9 openSUSE 15+ SUSE Enterprise 12 SP2+ Linux Mint 17+ Arch

Required Frameworks

All Operating Systems

.NET

Windows

VC++ Redistributable 17

Development

git .NET

Supported IDEs

Jetbrains Rider 2023.2+spaceVSCodespaceVisual Studio 2022 v17.7+

Getting Started

  • Install prerequisite requirements
  • Clone this repository (or download the latest):
    • git clone https://github.com/modernuo/ModernUO.git
  • Open ModernUO.sln to start developing

Building/Publishing

  • Run ./publish.cmd [release|debug (default: release)] [os] [arch (default: x64)]
    • os - Supported operating systems
      • win - Windows 10/11/2019/2022
      • osx - MacOS 11/12/13 (Big Sur, Monterey, Ventura)
      • linux - Linux
    • arch
      • x64 - Intel 64-bit
      • arm64 - ARM 64-bit (Windows Arm64 not supported)

Linux Prerequisites

Fedora, CentOS, RHEL, etc

dnf upgrade --refresh -y
# CentOS does not come with EPEL enabled
dnf install -y epel-release epel-next-release
dnf install -y findutils libicu zlib-devel zstd libargon2-devel tzdata

Ubuntu, Debian, etc

apt-get update -y
apt-get install -y libicu-dev libz-dev zstd libargon2-dev tzdata

Running the Server

  • Follow the publish instructions
  • Run ModernUO.exe or dotnet ModernUO.dll from the Distribution directory on the

Troubleshooting / FAQ

Want to sponsor?

Thank you for supporting us! You can find out how by visiting the sponsors page.

Collaborators

Kamron Batman Mark1145

Thanks

  • RunUO Team & Community
  • Voxpire, the ServUO Team & Community
  • Karasho, Jaedan and the ClassicUO Community



Development Tools & Plugins provided with โ™ฅ by
JetBrains Material Theme

modernuo's People

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

modernuo's Issues

Replace Types for loot/crafting

Lux had a great idea that has already been implemented on other shards.

We should replace the type lists for crafting/loot/etc that use Activator.CreateInstance (Reflection) with a factory function using lambda expression. This can be inline or accessed via a static function from the object's class.

e.g. (int amount = 1) => new Gold(amount)

Convert to .NET Core 3.0

  • Remove Reporting (HTML Renderers and Graphic Renderers)
    • A new system would most likely be external interface at the database/storage layer.
  • Replace Assembly Emitters for the command system
  • Remove Event Log
    • If this is a desired feature, it will most likely need to be in a drop-in plugin/nuget.

VendorGen never ends

Using [vendorgen never ends. After a world save it finishes and is incomplete.
No crash.

GenerateSpawners JSON crash

When attempting to load one of the distribution json spawner files the server will crash with the following, e.g. [generatespawners felucca.json

System.Text.Json.JsonException: The JSON value could not be converted to System.Collections.Generic.List`1[Server.Json.DynamicJson]. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
   at System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType)
   at System.Text.Json.JsonSerializer.HandleStartObject(JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
   at System.Text.Json.JsonSerializer.ReadCore(Type returnType, JsonSerializerOptions options, Utf8JsonReader& reader)
   at System.Text.Json.JsonSerializer.Deserialize(String json, Type returnType, JsonSerializerOptions options)
   at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
   at Server.Json.JsonConfig.Deserialize[T](String filePath, JsonSerializerOptions options) in /home/jabin/sources/ModernUO/Projects/Server/JsonConfiguration/JsonConfig.cs:line 60
   at Server.Engines.Spawners.GenerateSpawners.GenerateSpawners_OnCommand(CommandEventArgs e) in /home/jabin/sources/ModernUO/Projects/UOContent/Engines/Spawners/GenerateSpawners.cs:line 45
   at Server.CommandSystem.Handle(Mobile from, String text, MessageType type) in /home/jabin/sources/ModernUO/Projects/Server/Commands.cs:line 222
   at Server.Mobile.DoSpeech(String text, Int32[] keywords, MessageType type, Int32 hue) in /home/jabin/sources/ModernUO/Projects/Server/Mobile.cs:line 4866
   at Server.Mobiles.PlayerMobile.DoSpeech(String text, Int32[] keywords, MessageType type, Int32 hue) in /home/jabin/sources/ModernUO/Projects/UOContent/Mobiles/PlayerMobile.cs:line 1998
   at Server.Network.PacketHandlers.UnicodeSpeech(NetState state, PacketReader pvSrc) in /home/jabin/sources/ModernUO/Projects/Server/Network/PacketHandlers.cs:line 1324
   at Server.Network.MessagePumpService.DoWork() in /home/jabin/sources/ModernUO/Projects/Server/Network/MessagePumpService.cs:line 52
   at Server.Core.RunEventLoop(IMessagePumpService messagePumpService) in /home/jabin/sources/ModernUO/Projects/Server/Main.cs:line 424

However loading the region-spawners.json works fine.

Unify / Generalize Quest & Recipe Systems

  • Unify the old and newer quest systems
  • Update/generalize the recipe system
  • Remove quest/recipe related properties from PlayerMobile to reduce constructor/serialization weight
  • Set up serialization for the systems

Eliminate Activator.CreateInstance

Using Activator.CreateInstance to generate loot is kind of sucky. Look into a better method, potentially using new T() or factory methods?

Fix virtual properties/methods called during construction

With the change to arrow body expression and shorthand properties, lots of constructors have values assigned which may get overridden by a parent or vice versa when they shouldn't.

Might need to introduce a general Item/Mobile init function.

Cannot Target Statics

Looks like targeting statics is broken. This might be related to changes I made in loading static files.
Tested the following:

  • Teleporting as staff
  • Chopping wood

Website using Github Pages

We should have a welcoming website with the following:

  • Our goals.
  • What we have accomplished so far.
  • List of servers used for testing the distributions.
  • A really awesome logo (and icon #21)

Consolidate Region Area and BaseRegion Rectangles

Looks like Region takes Areas and breaks them down into non-overlapping rectangles.
We should just do this directly in BaseRegion so we are only storing one set.

This will make more sense after the BaseRegion Spawn code is removed entirely.

GetPoisonLevel Crash

Exception:
System.NullReferenceException: Object reference not set to an instance of an object.
   at Server.Items.BaseInstrument.GetPoisonLevel(BaseCreature bc) in C:\Users\Tony\Desktop\ModernUO-master\Projects\UOContent\Items\Skill Items\Musical Instruments\BaseInstrument.cs:line 240
   at Server.Items.BaseInstrument.GetBaseDifficulty(Mobile targ) in C:\Users\Tony\Desktop\ModernUO-master\Projects\UOContent\Items\Skill Items\Musical Instruments\BaseInstrument.cs:line 270
   at Server.Items.BaseInstrument.GetDifficultyFor(Mobile targ) in C:\Users\Tony\Desktop\ModernUO-master\Projects\UOContent\Items\Skill Items\Musical Instruments\BaseInstrument.cs:line 285
   at Server.SkillHandlers.Peacemaking.InternalTarget.OnTarget(Mobile from, Object targeted) in C:\Users\Tony\Desktop\ModernUO-master\Projects\UOContent\Skills\Peacemaking.cs:line 159
   at Server.Targeting.Target.Invoke(Mobile from, Object targeted) in C:\Users\Tony\Desktop\ModernUO-master\Projects\Server\Targeting\Target.cs:line 204
   at Server.Network.PacketHandlers.TargetResponse(NetState state, PacketReader pvSrc) in C:\Users\Tony\Desktop\ModernUO-master\Projects\Server\Network\PacketHandlers.cs:line 1097
   at Server.Network.MessagePumpService.DoWork() in C:\Users\Tony\Desktop\ModernUO-master\Projects\Server\Network\MessagePumpService.cs:line 51
   at Server.Core.RunEventLoop(IMessagePumpService messagePumpService) in C:\Users\Tony\Desktop\ModernUO-master\Projects\Server\Main.cs:line 421

Cannot sell to vendors, VendorSellReply packet length wrong

Related to #182, when the client attempts to sell to a vendor nothing happens.

The packet handler attempts to use the PacketReader.Length property in order to verify the packet is valid. However as the backing IMemoryOwner<byte> block for PacketReader always has a length of 4096 due to SlabMemoryPool's Rent(int size) implementation ignoring the size parameter and only returning memory blocks of the default size (4096). This causes the calculated length check to always return false making the sell request fail:

    public static void VendorSellReply(NetState state, PacketReader pvSrc)
    {
      Serial serial = pvSrc.ReadUInt32();
      var vendor = World.FindMobile(serial);

      if (vendor == null) return;

      if (vendor.Deleted || !Utility.RangeCheck(vendor.Location, state.Mobile.Location, 10))
      {
        state.Send(new EndVendorSell(vendor));
        return;
      }

      int count = pvSrc.ReadUInt16();

      if (count < 100 && pvSrc.Length == 4 + 2 + count * 6) // pvSrc.Length is always 4096
      {
        var sellList = new List<SellItemResponse>(count);

        for (var i = 0; i < count; i++)
        {
          var item = World.FindItem(pvSrc.ReadUInt32());
          int amount = pvSrc.ReadInt16();

          if (item != null && amount > 0)
            sellList.Add(new SellItemResponse(item, amount));
        }

        if (sellList.Count > 0 && vendor is IVendor v && v.OnSellItems(state.Mobile, sellList))
          state.Send(new EndVendorSell(vendor));
      }
    }

A workaround can be achieved by ensuring the packet header (Id + Length) doesn't get sliced by ProcessPacket (see #182) and then manually reading the length to use in the check:

    public static void VendorSellReply(NetState state, PacketReader pvSrc)
    {
      pvSrc.Seek(1, SeekOrigin.Begin); // The memory slab begins at the packet start
      int msgSize = pvSrc.ReadUInt16();
      Serial serial = pvSrc.ReadUInt32();
      var vendor = World.FindMobile(serial);

      if (vendor == null) return;

      if (vendor.Deleted || !Utility.RangeCheck(vendor.Location, state.Mobile.Location, 10))
      {
        state.Send(new EndVendorSell(vendor));
        return;
      }

      int count = pvSrc.ReadUInt16();

      if (count < 100 && msgSize == (1 + 2 + 4 + 2 + (count * 6))) // Use the packet message size, not the buffer size
      {
        var sellList = new List<SellItemResponse>(count);

        for (var i = 0; i < count; i++)
        {
          var item = World.FindItem(pvSrc.ReadUInt32());
          int amount = pvSrc.ReadInt16();

          if (item != null && amount > 0)
            sellList.Add(new SellItemResponse(item, amount));
        }

        if (sellList.Count > 0 && vendor is IVendor v && v.OnSellItems(state.Mobile, sellList))
          state.Send(new EndVendorSell(vendor));
      }
    }

Replace GetHashCode XOR

The GetHashCode overrides that xor integer values are not actually a good idea. Not even sure if the values would be unique against the contents.

These should be replaced with prime number multiply-add.

Replace NonGeneric IComparable/IComparer

All inheritance relying on NonGeneric IComparable/IComparer should be replaced with the generic where possible. Uses of generic object comparisons, if they exist, should also be replaced where possible.

Replace System.Net.Mail.SmtpClient

Replace email log code to fix the following warnings:

`System.Net.Mail.SmtpClient' is obsolete: `SmtpClient and its network of types are poorly designed, we strongly recommend you use https://github.com/jstedfast/MailKit and https://github.com/jstedfast/MimeKit instead'

Add support for ZLib-IPP

Add support for the Intel Performance Platform version of Zlib.
I am hesitant to use JTK's version because of reported issues.

If someone wants to optimize 1.2.8 or 1.2.11.1 with Intel IPP, that would be amazing!

Modernize the codebase w/ Fixes & Optimizations

Updates the codebase to the newest code paradigms and standards. This includes:

  • Using string interpolations
  • Removing default value initialization
  • Merging sequential checks
  • Using ?? (null coalescing) instead of ternary
  • Using null propagation where possible
  • Removing unused namespaces
  • Using arrow body expressions for properties where applicable
  • Using automatic property initializers
  • Removing redundant initializers including delegations
  • Removing implicit this
  • Using constructor initializers
  • Use type casting variables to stop double casting
  • Remove overloading in favor of default value parameters
  • Replace ArrayList, HashTable, and object[] states with typed collections.
  • Use in-line out variable declaration
  • Optimize the spell system by introducing a singular SpellTarget object and making all spells children of a TargetingSpell class. This reduces the number of internal target types and reuses code.
  • Optimize GetEntities (GetItems[InRange] and GetMobiles[InRange]) to use generics where possible
  • Update GetRegion to use generics
  • Replace callbacks with object states with lambda curries
  • Remove Timer.DelayCall generic TimerStateCallback in favor of lambdas/closure/curries

In Progress:

  • Remove overloading in favor of named parameters
  • Optimize GetEntities to take a flexible set of predicates so that items/mobiles are filtered in the LINQ
    • e.g. Extending SelectItems, SelectMobiles, SelectMultis, etc

PRs:
#1 - Updates code formatting, style, fixes various small bugs, and changes casts/type checks to use pattern matching
#3, #37- Updates out variables, adding items with optional parameters in ctor, and makes functions that take typeof variables use generics.
#7 - Fixes Dictionary uses throughout repo
#14 - More cleanup
#18 - Collapsing more null checks and removing overloading constructors
#31 - Fix comparables
#36 - Cleans up SpellTargeting

Replace Kestrel with Sockets

Looks like libuv is being deprecated and the performance of managed sockets should be good enough.

Let's go back to regular sockets and wire that to a custom pipe in order to simplify the flow. It should look something like this:

  1. Construct Packet using stackalloc
  2. Get Span from Pipe
  3. Huffman encode the packet to the span
  4. Advance the pipe
  5. At end of the loop, flush entire pipe for all clients to the sockets.

Tangentially will need to decide if we use libuv for the thread and/or timers.

Optimize Map/Sector Range checks

Opportunities for improving the GetXInRange checks for high number of players/mobiles in a specific area. It looks like large shards are getting CPU lag spikes specifically due to this.

@jaedan identified some ways of optimizing this to reduce high CPU load.

Split Layered Items from Stackable Items

Split layered items from stackable items since there are no countable equippable items.
Even an item like a throwable (BaseThrown on ServUO) doesn't have an actual "Amount".

Tools that have a UsesRemaining or amount-ish property do not use stackable Amount.

Cannot buy from vendors, VendorBuyReply packet truncated

The client vendor buy reply packet is sent whenever a player purchases an item from an NPC vendor. However to the client nothing appears to happen once you finish buying from the vendor. I've narrowed down the issue to a packet handling problem.

The VendorBuyReply packet handler requires the message size in order to read the list of items requested to be purchased:

// PacketHandlers.cs#L500
      pvSrc.Seek(1, SeekOrigin.Begin);

      int msgSize = pvSrc.ReadUInt16();
      var vendor = World.FindMobile(pvSrc.ReadUInt32());
      var flag = pvSrc.ReadByte();

      if (vendor == null)
        return;

However at this point the message size has already been truncated by the main ProcessPacket function, which slices the packet after the final position containing the Packet Id and Packet Length:

// PacketHandlers.cs#L350
      var packet = seq.Slice(r.Position);
      var memOwner = _memoryPool.Rent((int)packet.Length);

      packet.CopyTo(memOwner.Memory.Span);

      pump.QueueWork(ns, memOwner, handler.OnReceive);

The VendorBuyReply packet handler expects to receive all the packet data, however it's offset, so the msg size and serial are instead read out of the buy list data and come out all garbled. The information about the packet size doesn't seem to get preserved anywhere in the PacketReader to replace the ReadUInt16 call from what I could see.

I would submit a PR however with the new packet updates coming and this not being a simple change I figured it would be best to raise it here.

I'm using a temporary workaround in ProcessPacket:

// PacketHandlers.cs#L350
      if (packetId == 0x3B)
        r.Seek(0, SeekOrigin.Begin);

Replace double values (e.g. Skill values) with their integer counterparts.

It looks like some legacy code still references the double value (converted from underlying integer value) for skills. This should be completely converted. The doubles are converted to ushort for the client under the hood, so all calculations/references should be changed to eliminate the doubles.

Fix New Mobile Animation

I deleted the new mobile animation code. It needs to be put back for Stygian Abyss / Gargoyles (Flying).

Optimize Books

While it seems trivial, this low hanging fruit should be straight forward.
Books are 20-40 pages and each one has an array of 40 page objects with empty line arrays.

Optimize this to use a linked list or at least an array of nulls. Could also pull from a pool of page objects to lower allocations.

This will also optimize the packets being sent.

SignGen command crash

Using [signgen crashes the shard

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at Server.Commands.SignParser.Parse(Mobile from) in Y:\Repositories\ModernUO\Projects\Scripts\Commands\SignParser.cs:line 25
   at Server.Commands.SignParser.SignGen_OnCommand(CommandEventArgs c) in Y:\Repositories\ModernUO\Projects\Scripts\Commands\SignParser.cs:line 21
   at Server.CommandSystem.Handle(Mobile from, String text, MessageType type) in Y:\Repositories\ModernUO\Projects\Server\Commands.cs:line 217
   at Server.Mobile.DoSpeech(String text, Int32[] keywords, MessageType type, Int32 hue) in Y:\Repositories\ModernUO\Projects\Server\Mobile.cs:line 4903
   at Server.Mobiles.PlayerMobile.DoSpeech(String text, Int32[] keywords, MessageType type, Int32 hue) in Y:\Repositories\ModernUO\Projects\Scripts\Mobiles\PlayerMobile.cs:line 1999
   at Server.Network.PacketHandlers.UnicodeSpeech(NetState state, PacketReader pvSrc) in Y:\Repositories\ModernUO\Projects\Server\Network\PacketHandlers.cs:line 1340
   at Server.Network.MessagePump.DoWork() in Y:\Repositories\ModernUO\Projects\Server\Network\MessagePump.cs:line 58
   at Server.Core.Main(String[] args) in Y:\Repositories\ModernUO\Projects\Server\Main.cs:line 482

Define minimum weight (prevent negatives)

Hey, in my tinkering with runuo 2.5 and 2.6 i noticed that if negative weight compounded beyond a certain limit it would default to max weight. I wanted to make a bag that would randomly generate with a weight from 1 to -150 and thus would allow an extra 100 ores (in that area). I got the bag to spawn off of an npc vendor but when i started bug checking the bag i ran into all kinds of default weight errors.

Things i noticed:

Stacking negitive weight bags with no other items would additionally subtract weight through the chain of bags until the player weight reached some sort of threshold and defaulted to max weight.

Having multiple items in a bag with negative weight subtracted as it should but the weight modifier could not keep up with alot of fast changes (bag sorting, pot use, so on) and defaulted to max weight.

Negative weight bags on pets with pack did nothing so far as i could see.

So i concluded that deffing a minimum negative weight would resolve most of the issues i was having the consequence i was going to use was not being able to pick items off of the ground if player weight fell below a minimum weight. Thus using it would require planning.

I searched around alot for similar errors but never really found a good solution.

The last thing i was working on was getting the player total weight and subtracting 200 if the weight exceeded the players carry capacity before stamina burn.

Ill post my scripts on runuo's git when i can. I figured that if your going to rework the entire arcitecture deffining minium weight and some negitive handeling would prevent alot of needless crashing.

Excuse by bad spelling.

HouseFoundation has bad locks

According to JB, HouseFoundation has several variables that are used in and out of locks, making the variables volatile. This should be redesigned/fixed, and if possible, with locks eliminated entirely.

Update Settings

  • Fix ipLImiter to ipLimiter (capitalization)
  • Fix tense. Change enabled to enable
  • Add veteran reward setting for reward interval
  • Add account security password protection schema. Value should be Argon2
  • Fix vetReards to vetRewards
  • Add other settings I can't think of right now since it is late.

Replace resources w/ generic commodity object

  • Replace all commodities (gold, logs, ore, ingots, etc) with a single Commodity type.
  • Use an object pool to rent/return these objects.
  • Replace Type arguments with Enum arguments for these commodities.
  • Replace Activator.CreateInstance with Rent from the object pool.
  • Replace getting items in a container by type with the enum.
  • Update hold and stack methods to be aware of the new commodity object.
  • Create a migration script from the old RunUO types.
  • Update mobiles/loot to allocate gold and other items through the object pool.

Fix localization comments that are corrupted

During the automatic cleanup many files were converted from other wrong encodings back to UTF-8. This process corrupted many comments (mainly localization text). This should be fixed by pasting back the proper text.

Use stackalloc where possible

There are several places where arrays are temporarily used. These arrays come from one or another type of pooling, are allocated as a managed array, or use a statically initialized array that violates thread safety.

These instances should be replaced with stackalloc or equiv techniques.

Fix Houses to use a 3D instead of 2D Region

Update the housing system to use 3D regions instead of 2D. This will allow townhouse and other systems to easily integrate without causing region issues that would allow exploitation.

Integrate Libuv

@jaedan had a great idea to integrate libuv using it as the engine loop and socket system.
This would give us the added performance like ASPNET Core.

Create actual logging

  • Use Microsoft.Extensions.Logging to create a logging system.

  • Replace Console.WriteLine with Logging

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.