Git Product home page Git Product logo

slimux's Introduction

NOTE: This repository is not actively maintained anymore. You have an active fork please add a comment to this issue so others can find it, thanks!

Slimux

This is a SLIME inspired tmux integration plugin for Vim. It makes it easy to interact with different tmux panes directly from Vim. It has two styles for interacting with panes. REPL and Shell styles.

REPL commands are designed to work with various Read Eval Print Loops such as python, irb (Ruby), node (Javascript), coffee (CoffeeScript) etc. This is loosely modelled after SLIME for Emacs. Shell commands are designed to work with normal shells such as bash. These are useful for running tests for example.

Main difference between these is pane configuration visibility. Each buffer has own configuration for REPL, but for Shell there is only one global configuration. The configuration is prompted from user when the commands are used for the first time. The configuration happens interactively. You will see list of available tmux panes and you can choose one by hitting enter on top of one.

Also REPL commands can have custom pre, post and escape hooks. These allows interaction with some more complex REPLs such as the CoffeeScript REPL.

This plugin borrows ideas and some code from vim-slime.

Blog post

http://esa-matti.suuronen.org/blog/2012/04/19/slimux-tmux-plugin-for-vim/

Ascii.io screencast

https://asciinema.org/a/409

Installation

Use pathogen and put files to $HOME/.vim/bundle/slimux/

Slimux requires fairly recent tmux version. Be sure you have 1.5.x or later.

REPL Commands

SlimuxREPLSendLine

Send current line to the configured pane.

SlimuxREPLSendSelection

Send last visually selected text to the configured pane.

SlimuxREPLSendBuffer

Send current buffer to the configured pane.

SlimuxREPLConfigure

Prompt pane configuration for the current buffer.

Shell Commands

SlimuxShellPrompt

Prompt for a shell command and send it to the configured tmux pane.

SlimuxShellLast

Rerun last shell command(prompts for a shell command if none was run before).

SlimuxShellRun

Specify a shell command to run directly, without the prompt:

:SlimuxShellRun rspec spec/foo_spec.rb

Suitable for mapping and other automation.

Note that you need to escape strings intended for the shell. E.g. to list files with actual asterisks in their name:

:SlimuxShellRun ls *\**

SlimuxShellConfigure [pane-id]

Select the tmux pane to which shell commands will be sent. If executed without a parameter it prompts global pane configuration for the shell commands. If called with parameter it selects the pane without user interaction, which will aid multi-pane workflows. Parameter is the tmux pane identifier in \d:\d:\d form and completed automatically with cline completion.

Sending Keys

SlimuxSendKeysPrompt

Prompt for a key sequence using the 'tmux send-keys' syntax and send it to a configured tmux pane. E.g. Lets say you want to stop the webserver currently running in a shell(ctrl+c) and restart it(assuming the command to start is 'make run-server'):

:SlimuxSendKeysPrompt
KEYS>C-C 'make run-server' Enter

or run previous command with

KEYS>Up Enter

In short, some strings such as 'C-C' or 'Enter' have special meanings, while others are sent as a sequence of character keys(in the above example, 'make run-server')

SlimuxSendKeysLast

Resends the last key sequence sent(prompts for a sequence if none was sent before).

SlimuxSendKeysConfigure

Prompt global pane configuration to send the key sequence.

Keyboard Shortcuts

Slimux does not force any shortcuts on your Vim, but here's something you can put to your .vimrc

map <Leader>s :SlimuxREPLSendLine<CR>
vmap <Leader>s :SlimuxREPLSendSelection<CR>
map <Leader>b :SlimuxREPLSendBuffer<CR>
map <Leader>a :SlimuxShellLast<CR>
map <Leader>k :SlimuxSendKeysLast<CR>

Or if you like something more Emacs Slime style try something like this:

map <C-c><C-c> :SlimuxREPLSendLine<CR>
vmap <C-c><C-c> :SlimuxREPLSendSelection<CR>

You may also add shortcuts to other commands too.

For Scheme/Racket Slimux has few extra bindings. Enable them with

let g:slimux_scheme_keybindings=1
let g:slimux_racket_keybindings=1

For more information refer to the scheme plugin header.

Adding support for new languages

Usually new there is no need to do anything. For example Ruby and Node.js REPLs works just fine out of box, but for some languages you have to do some preprocessing before the code can be sent. There are three hooks you can specify for each language.

Custom escaping function

function SlimuxEscape_<filetype>(text)
    return a:text
endfunction

Pre send hook

function SlimuxPre_<filetype>(target_pane)
endfunction

Post send hook

function SlimuxPost_<filetype>(target_pane)
endfunction

Just add these to ftplugin directory contained within this plugin (and sent a pull request on Github!). You can use Python and CoffeeScript hooks as examples.

Options

  • g:slimux_tmux_path = /path/to/your/tmux sets the path to the preferred tmux binary, if not specified, defaults to getting tmux command from path using system('command -v tmux').

  • g:slimux_select_from_current_window = 1 select panes only from current window. Defaults to 0 to select panes from all tmux panes.

  • g:slimux_pane_format customize the formatting of the panes, see the FORMATS section in man tmux.
    The string "#{pane_id}: " is always prepended to the format so Slimux can identify the selected pane.

Other Vim Slime plugins

Before I created this plugin I tried several others, but non of them satisfied me. They where too complicated or just didn't support the languages I needed. So if Slimux isn't your cup of tea, maybe one of these is:

slimux's People

Contributors

alvinfrancis avatar brian-stripe avatar bristi avatar chlunde avatar dvbuntu avatar esamattis avatar henrik avatar ivan-cukic avatar karadaharu avatar lotabout avatar oferreir avatar slashfoo avatar sternenseemann avatar sunaku avatar tarruda avatar toupeira avatar umitkablan 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

slimux's Issues

[RFE] Haskell support.

Would it be possible to add some bits to make Haskell support nicer?

like if you are on a line with
main :: IO ()
it sends
:t main
to ghci.

Kind Regards,

protocol version mismatch

Hi,

I updated the linux version from centos 6 to centos 7, and when I try to send command with slimux to another tmux panel, I'm told
"
Enter: Select pane - Space/x: Test - C-c/q: Cancel

protocol version mismatch (client 7, server 8)
No additional panes found
"
image
Am I the only one who meet this problem in centos 7? How could I handle this ?
Thanks a lot!

Allow ranges

Does Slimux support ranges, like '5\s' to send the next 5 lines (similar to '5dd')? I get an E481: No range allowed if I try...

[A characters from KEYS>C-C Up Enter

I tried to setup "run the last command again" shortcut using the SlimuxSendKeys command.

Like this:

:SlimuxSendKeysPrompt
KEYS>C-C Up Enter

but it outputs

$ [A
[A: command not found

for some reason. It can be worked around like this

KEYS>C-C Enter Up Enter

Can you take a look at this @tarruda?

SlimuxSendKeys() bug?

I'm experiencing a problem, could this be a bug or am I doing something wrong? I'm using Vim 8.0.55 in tmux 2.3, Mac OS Sierra. Thank you!

:SlimuxSendKeys 'anything' <CR>
OR
:SlimuxSendKeys "traceback()" <CR>

Error detected while processing function SlimuxSendKeys[4]..<SNR>92_Send:
line   31:
E115: Missing quote: ' send-keys -t " . target . " " . keys)
E116: Invalid arguments for function system

Make current pane as default target pane

It would be great if I can set the current pane as default target pane. So that I don't need to config it for every new opened/reopened pane and no need to select the target pane among a list of panes. And it can also avoid the situation when you select a wrong pane, it could be messed up by the codes sent to it.

vim hanging when using SlimuxREPLSendLine

Hello,
Great plugin, invaluable to me. Having issues however, may have been on upgrade to iTerm2 3.0, not sure.

When I issue a SlimuxREPLSendLine, MacVim is unresponsive, with the cursor remaining in the vim command line (bottom).

Looking at running processes, seems to be tmux load-buffer -b Slimux - the command that is causing the hanging. Killing that allows me to continue using vim.

Obviously I'm not able to send text out to the REPL however.

Repository maintenance

It seems like this repository has not been updated for the last 4 years, even though there have been pull requests throughout this time.

To me personally, this repo represents the core of my workflow, so I would love to see it continue being maintained.

@esamattis any vision on potential further development or should there be an official fork that continues development?

IndentationError: unindent does not match any outer indentation level (Extra spaces produced in IPython)

This works perfectly fine ;

vim -

for i in range(1):
        for j in range(1):
                print 'Hello'

IPython [Using SlimuxREPLSendSelection] -

In [54]: for i in range(1):
   ....:        for j in range(1):
   ....:                        print 'Hello'
   ....: 
Hello

*Notice the spaces in my second indentation.

So when i try to indent back and do anything -

vim -

for i in range(1):
        for j in range(1):
                print 'Hello'
        print 'BUG!'

IPython -

In [55]: for i in range(1):
   ....:        for j in range(1):
   ....:                        print 'Hello'
   ....:                print 'BUG!'
   ....: 
  File "<ipython-input-55-007af182e978>", line 4
    print 'BUG!'
                ^
IndentationError: unindent does not match any outer indentation level

If you want to paste code into IPython, try the %paste and %cpaste magic functions.



IPython version : 4.2.1
vim version : 7.4

Any help would be appreciated, I really want to continue using Slimux.

Thank you.

SlimuxREPLSendLine fails with Python

I'm unable to send a single line (both with and without visual mode). Actually, only thing that works for me, is selecting more than one line in visual mode and using SlimuxREPLSendSelection.

Error detected while processing function SlimuxSendCode..<SNR>35_Send..<SNR>35_ExecFileTypeFn..SlimuxEscape_python:                             
line   44:                          
E121: Undefined variable: l:at_indent0
E15: Invalid expression: !l:at_indent0

@epeli confirmed that this is a Python-specific issue.

Python REPL IndentationError: unexpected indent

Everything works as expected however when sending an indented line, slimux doesn't cut indentation according the first line as I'd expect after looking at slimux/ftplugin/python.vim

The output of :scriptnames lists the ftplugin, so I guess it's loaded. I tried sourcing it manually, still doesn't work.

Test file:

def test():
    print "hello"

:SlimuxREPLSendLine on the second line has the problem.

Vim log (truncated, started vim with -V9):

Executing BufEnter Auto commands for "*"
autocommand if (winnr("$") == 1 && exists("b:NERDTreeType") && b:NERDTreeType == "primary") | q | endif

Executing BufEnter Auto commands for "*"
autocommand sil! call s:LocalBrowse(expand("<amatch>"))

Calling shell to execute: "(tmux set-buffer -- '    print "hello"^M') >/tmp/vBj0Yn7/1 2>&1"
Calling shell to execute: "(tmux paste-buffer -t %1) >/tmp/vBj0Yn7/2 2>&1"
Executing CursorMoved Auto commands for "*"
autocommand call eclim#util#ShowCurrentError()

NerdTree before, eclim after, I am not sure whether it should display invoking SlimuxEscape_python.

Error after sending visual selection to ipython with vim splits

I noticed an error after sending a visual selection with python code containing imports. To reproduce this issue:

1 - Initiate tmux and create two panes (in my case, I hit C-b+").
2 - In the first pane, open a file with vim (I personally use neovim). In the second pane, start a session with ipython.
3 - In the pane you started vim, create a vertical split with vim (C-W v)
4 - (Optional) Open another file in the second vertical split created in step 3.
5 - Write some python imports in the first part of the vertical split

import sys
import os

6 - Visually select those lines and send them to the ipython pane
7 - This will trigger an error

I attach a couple of screenshots to make the explanation easier to follow.

screenshot from 2016-04-03 10-47-59

screenshot from 2016-04-03 10-21-46

For some reason, this only happens with imports.

Version information: tmux 2.0, Ubuntu GNOME 15.10, latest version of slimux.

Thanks

Don't try to send to pane that doesn't exist anymore

  1. Open Vim and set a target pane, e.g. with :SlimuxREPLConfigure
  2. Close the target pane
  3. Try to send something from Vim to the target pane

The last step silently fails. Could Slimux prompt for a new target pane instead?

Escaping R Code

This is a great plugin that I use almost every day.

However, I have been facing issues with sending R code to the console. Whenever the code is small, I can send it to the console without any problem. However, when I select a big chunk and send to the console it breaks.

It seems that when the code is pasted on the console via tmux paste-buffer, it gets somehow duplicated and I get an error. Whenever I copy and paste manually, the code is pasted correctly. Thus, I am not sure how to correct this problem.

I gave a go at escaping the R code by writing a custom function without any success:

function! SlimuxEscape_r(text)

    "" Remove all empty lines and use soft linebreaks
    let no_empty_lines = substitute(a:text, '\n\s*\ze\n', "", "g")
    let no_empty_lines = substitute(no_empty_lines, "\n", "
", "g")

    "" See if any non-empty lines sent at all
    if no_empty_lines == "
"
        return "
"
    endif

    "" Return the processed lines
    return l:no_empty_lines, "
")."
"

endfunction

As an illustration, take the following code:

        data.frame(
            Intercept=1,
            #aaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaa,
            #aaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaa,
            a = 23,
            #aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaaa,
            #aaa = aaaa$aaa,
            #aaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaaa,
            b = 34,
            #aaaaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaaaa,
            c = 56,
            #aaaaaaaaaa = aaaa$aaaaaaaaaa,
            #aaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaa,
            #aaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaa,
            d = 56 #,
            #aaaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaaa,
            #aaaaaaaaaaaaaa = aaaa$aaaaaaaaaaaaaa,
            #aaaaaaaaaaa = aaaa$aaaaaaaaaaa
            )

Whenever I send to the console via :SlimuxREPLSendSelection<CR>. The code is not pasted correctly and I get an error:

Error in data.frame(Intercept = 1, a = 23, b = 34, c = 56, aa$aaaaaaaaaaaaa,  :
  object 'aa' not found

However, if I copy and paste the above in the console it run without any problems.

Has anybody experienced a similar issue? Any way to fix it?

how to use the Slimux in tmux?

hi,guys.I see the video from @dvbuntu and decide to use the Slimux.
I install it by Vundle,not the pathogen.
Then i set the configure.
ww
After that ,i want to test it .
But i don't how to use it in the tmux.
ee

i use the C-c,C-c in the vim and C-b o change to another window, Then i don't know how to do .
Does everyone give me am example. Thanks.

Is there any way to give a name to tmux pane?

Slimux works quite well here.
But sometimes I split the panes, then the names of panes get messed up. Slimux gets confused of which pane to send the content.

Is there any way to bound slimux to a fixed pane?

Vim help

It'd be cool if

:help slimux

brought up some of the documentation, just the commands in the readme and what they do would be great.

Calling nmap :SlimuxREPLSendLine changes cursor position.

E.g. I have the following mapping
nmap j :SlimuxREPLSendLine

After sending a line to a tmux pane, the cursor is placed to the beginning of that line.
A lot of the time, I send line to tmux in insert mode using "j", and it is very inconvenient that the cursor position changes after that.

Would be nice if SlimuxREPLSendLine can be change to not change cursor position.

Vim to Vim in Normal mode

Thank you for this plugin and your work.

I would like to report that sending from one vim to another works well in insert mode (as far as I have tried; i am a new user).

However, when the target vim is in normal mode the text is sent to a different location than the cursor position. It seems to prefer a particular position (i.e. it does not seem random as per my use).

It would be great if this would be solved. That is sending to another vim in normal mode would send the text to the position of the cursor.

Thank you

Slimux broken in IPython 5

When the user sends a visual selection to a pane with IPython 5, slimux only sends the first line. Here is a screenshot the show the result after visual selection (selecting both lines) and <C-c><C-c>:

screenshot from 2016-07-12 22-40-24

By the way, excellent plugin.

Screencast?

Is that screencast still available? The link seems broken.

Make SlimuxSendKeysLast send last prompted-for keys instead of last sent keys

SlimuxSendKeysLast prompts if one hasn't specified what to send, and then keeps sending that.

When someone uses SlimuxSendKeys command to send keys, however, the last sent gets overwritten and one would need to re-enter what was typed at the prompt.

I think separating the last-sent from the path by SlimuxSendKeys, and only involve the *Prompt and *Last commands it would avoid this problem.

Send text object to REPL

It would be really great if it was possible to send any text object to REPL. For example, if I bind this function to gs, I would be able to send 3 lines with gs2j, or 2 paragraphs with gs2ap. Or if I have a text object for entire buffer ae, I could type gsae to send the buffer.

I've come up with this:

" Send text object to tmux pane via slimux
nnoremap <silent> gs :<C-u>set opfunc=SlimuxREPLSendTextObject<CR>g@
nnoremap <silent> gss :SlimuxREPLSendLine<CR>
vnoremap <silent> gs :SlimuxREPLSendSelection<CR>

function! SlimuxREPLSendTextObject(type, ...) abort
  let saved_unnamed_register = @@

  silent exe "normal! '[V']y"
  '[,']SlimuxREPLSendSelection

  let @@ = saved_unnamed_register
endfunction

Note that it does not work with sub-line text objects, like iw.

Sending selection by stripping comments

In some cases there can be quite a few comment lines in the selected range and sending the comments to the target pane makes no sense. It would be great to have a flag/argument to SlimuxREPLSendSelection to strip out the comments before sending the selection to the target pane.

Slimux not Affecting the Selected Tmux Pane

Hello,

I just found out about Slimux (having previously been using vim-slime), and am excited to try it out! However, I haven't been able to get Slimux working, and so am wondering whether I'm doing something wrong, or if there might be a compatibility bug with my version of Tmux and/or Vim.

Versions:

  • tmux -V tells me that I'm using version 1.9a
  • vim --version tells me that I'm using version "7.4 (2013 Aug 10)"
  • I'm using the master branch of Slimux, at the current commit (as of this writing), f8ae770. I installed it using Pathogen. I know that the install worked, because Vim recognizes the Slimux commands and doesn't give any error messages when I try to use them.

Replicating the Issue:

Here are the steps I'm taking when trying to use Slimux:

  1. Start a tmux session with tmux new-session -s "Test"
  2. Split the tmux window with Ctrl+b %
  3. In one pane of the split tmux window, launch R (or python)
  4. In the other pane, launch vim
  5. In vim:
    1. Write 5+5
    2. Navigate the cursor to be on the same line as the 5+5
    3. In normal mode, do :SlimuxREPLSendLine
      1. Slimux now prompts me to select a tmux window.
        • I can navigate up and down. However, when I press the spacebar, nothing happens (no overlay of which window is which)
        • Using the Slimux selection window, I select the tmux pane that's running R or python, and press Enter.
        • Vim's status bar says ":SlimuxREPLSendLine" (i.e., it was recognized as a command, with no errors), but nothing happens in the other tmux pane.
  • Nothing happens in the other tmux pane when I use SlimuxShellRun, either (e.g., with just bash running in the other tmux pane, using :SlimuxShellRun ls *\** in vim).
  • SlimuxSendKeysPrompt and SlimuxSendKeysLast do work, however.

Am I forgetting to set something up here? From the Readme and blog posts I've read, I'm unsure whether there's more setup I should be doing.

Slimux ignores a pane if vim is run outside tmux

I run vim outside tmux and my REPL inside. In this setup something went broken lately - Slimux "eats" one pane, when I have one pane open it says there are none, if there are multiple, it seems to ignore the first.

When I set
let g:slimux_exclude_vim_pane = 0

it works correctly again, so it seems that this filtering breaks down somehow if vim itself is not inside tmux, I guess. It should not be necessary to set this option if vim is not even inside tmux.

Allow SendSelection to use marks and ranges

In situations where you are making tweaks and repeatedly sending the same section of code, it would be helpful if you could just use marks and send a command like:
'a,'bSlimuxREPLSendSelection

Julia for loop break

When I send a block of code under visual mode to the repl it always breaks half way through a for loop:

screenshot from 2015-11-05 10-17-28

Suggest panes only from current session.

Firstly, thanks for writing such an awesome plugin. Just one request, is it possible to configure slimux in any way such that when doing SlimuxREPLConfigure, it only suggests panes from the active session and not all the tmux sessions. I usually have more than one tmux session running, and it therefore ends up suggesting a long list of panes.

Thanks

using fish instead of bash causing problems

I've been using slimux for half a year now and I love it. Until recently I've been using bash as my default shell, but now I have really been enjoying fish (friendly interactive shell). I have found a problem whereby within a fish shell I start tmux, create two panes, open vim in the top pane and my repl in the bottom pane, I send the first line and hence select the bottom pane, but it appears in the top pane! The lines of vim get send back to vim and not to the repl!

If I repeat the above procedure from bash it works fine. Does anyone know what could cause this?
Thanks :)

slimux seems to only work after first install

using vundle and installing works great, but when I quit vim, the slimux commands are never available again. has anybody seen anything like this?

I have never seen a problem like this before.

cheers!

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.