GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — use cmap library for colormaps by tlambert03 · Pull Request #390 · fastplotlib/fastplotlib

Conversation

@tlambert03

@tlambert03 tlambert03 commented Dec 4, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

this PR is an example of using https://github.com/tlambert03/cmap instead of matplotlib for colormaps.

It does add cmap to setup.py ... but if you'd prefer not to go that far, we could guard it all behind an import and say "must install cmap to display stuff with colormaps"

closes #387

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

almarklein reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
tlambert03 added 3 commits December 4, 2023 12:21
@tlambert03
example with cmap
f74632c
@tlambert03
add to deps
9d59c8b
@tlambert03
fix shape
6d8025a
@kushalkolar

kushalkolar commented Dec 4, 2023

Copy link
Copy Markdown
Member

Seems like there are slight color differences between the cmap library and matplotlib ones? You can download the screenshot diffs at the bottom: https://github.com/fastplotlib/fastplotlib/actions/runs/7090258613

I don't think it's an issue, but I'm curious why it's different.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tlambert03

tlambert03 commented Dec 4, 2023

Copy link
Copy Markdown
Contributor Author

thanks for the heads up @kushalkolar. I'll have a look at it and figure out what's going on.

I do actually test for parity with matplotlib here (both naming and the actual effect of applying the cmap to an image), so i suspect that the differences might be in the way that colormaps are actually applied in the functions module. I did notice a very slight difference in the values of get_cmap as well, so I suspect that might be the root of it. I'll do some digging and get back to you :)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tlambert03

tlambert03 commented Dec 4, 2023

Copy link
Copy Markdown
Contributor Author

btw, I'd like to run these tests locally, but i ran into #388 ... any thoughts there?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Dec 4, 2023

Copy link
Copy Markdown
Member

Thanks!

Everything in the regenerate screenshots workflow seems fine visually, so you can replace the ground truth of the failing tests with those.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tlambert03 tlambert03 mentioned this pull request Dec 6, 2023
Tests: OSError: [Errno 24] Too many open files #388
Closed
tlambert03 added 8 commits December 7, 2023 15:49
@tlambert03
use full map
05f7620
@tlambert03
remove break
769284a
@tlambert03
undo changes to screenshots
bc0c2f8
@tlambert03
fix parse
a428a62
@tlambert03
remove diffs
45f1a14
@tlambert03
Merge branch 'main' into cmap
92841e7
@tlambert03
remove x.py
18b6018
@tlambert03
minimize diff
4895760
@tlambert03 tlambert03 changed the title example using cmap use cmap library for colormaps Dec 7, 2023
kushalkolar
kushalkolar requested changes Dec 7, 2023
View reviewed changes

@kushalkolar kushalkolar left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than that docstring lgtm! The colormap text files can now be removed too.

Curious what the difference was previously when the colors weren't matching?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread fastplotlib/utils/functions.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@tlambert03

tlambert03 commented Dec 7, 2023

Copy link
Copy Markdown
Contributor Author

Curious what the difference was previously when the colors weren't matching?

oh good. it's working on CI too!
Yeah, the difference is actually a good one for you to know about:

the cmap.Colormap object behaves very much like a matplotlib.colors.Colormap, with the main API being the __call__ method, which takes an array of scalars and returns an array of colors. And, just like the matplotlib API, if the input array is of dtype float, it expects values from 0-1, and it's of dtype int, it expects 0-255.

In [27]: import cmap

In [28]: viridis = cmap.Colormap('viridis')

In [29]: viridis(np.linspace(0, 255, 5, dtype=int))
Out[29]:

array([[0.267004, 0.004874, 0.329415, 1.      ],
       [0.231674, 0.318106, 0.544834, 1.      ],
       [0.128729, 0.563265, 0.551229, 1.      ],
       [0.360741, 0.785964, 0.387814, 1.      ],
       [0.993248, 0.906157, 0.143936, 1.      ]])

In [31]: from matplotlib import colormaps

In [32]: mpl_viridis = colormaps['viridis']

In [33]: mpl_viridis(np.linspace(0, 255, 5, dtype=int))
Out[33]:

array([[0.267004, 0.004874, 0.329415, 1.      ],
       [0.231674, 0.318106, 0.544834, 1.      ],
       [0.128729, 0.563265, 0.551229, 1.      ],
       [0.360741, 0.785964, 0.387814, 1.      ],
       [0.993248, 0.906157, 0.143936, 1.      ]])

There's of course a subtle difference in the input array there, for N evenly spaced numbers:

In [35]: np.linspace(0, 1, 5, dtype=float)
Out[35]: array([0.  , 0.25, 0.5 , 0.75, 1.  ])

In [36]: np.linspace(0, 255, 5, dtype=int)/255
Out[36]: array([0.        , 0.24705882, 0.49803922, 0.74901961, 1.        ])

and

In [29]: viridis(np.linspace(0, 255, 5, dtype=int))
Out[29]:

array([[0.267004, 0.004874, 0.329415, 1.      ],
       [0.231674, 0.318106, 0.544834, 1.      ],
       [0.128729, 0.563265, 0.551229, 1.      ],
       [0.360741, 0.785964, 0.387814, 1.      ],
       [0.993248, 0.906157, 0.143936, 1.      ]])

In [30]: viridis(np.linspace(0, 1, 5, dtype=float))
Out[30]:

array([[0.267004, 0.004874, 0.329415, 1.      ],
       [0.229739, 0.322361, 0.545706, 1.      ],
       [0.127568, 0.566949, 0.550556, 1.      ],
       [0.369214, 0.788888, 0.382914, 1.      ],
       [0.993248, 0.906157, 0.143936, 1.      ]])

... so, in my original PR, I used a slightly lower level construct to retrieve the N evenly spaced colors. Rather than using Colormap.__call__(some_array), I used Colormap.lut(n_colors) ... which was slightly different than the existing code you had here which used np.take on a linspace array of int:

In [37]: viridis.lut(5)
Out[37]:

array([[0.267004  , 0.004874  , 0.329415  , 1.        ],
       [0.23022275, 0.32129725, 0.545488  , 1.        ],
       [0.1281485 , 0.565107  , 0.5508925 , 1.        ],
       [0.36285925, 0.786695  , 0.386589  , 1.        ],
       [0.993248  , 0.906157  , 0.143936  , 1.        ]])

so I switched it to the __call__ approach and then everything matched the current screenshots. probably visually imperceptible, but might as well keep the same behavior :) Don't hesitate to ask if you have any questions about the cmap object. But in general, the __call__ method was designed (and tested) to behave exactly like matplotlibs.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tlambert03
add docstring
9071565
@tlambert03

tlambert03 commented Dec 7, 2023

Copy link
Copy Markdown
Contributor Author

The colormap text files can now be removed too.

oh wow... to be honest, I somehow missed the distinction there that matplotlib was only being used as a fallback.

So, a question for you: I can definitely understand wanting to keep dependencies to the absolute minimum. So, would you like me to update this PR slightly to keep the current behavior for named colormaps that you already bundle, remove cmap from setup.py and fallback to cmap only in the case that a string name is unrecognized? That would still allow you to support custom colormaps using all the previously discussed syntax, but the user would have to opt-in to that behavior. Thoughts?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Dec 8, 2023

Copy link
Copy Markdown
Member

There's of course a subtle difference in the input array there, for N evenly spaced numbers:

In [35]: np.linspace(0, 1, 5, dtype=float)
Out[35]: array([0.  , 0.25, 0.5 , 0.75, 1.  ])

In [36]: np.linspace(0, 255, 5, dtype=int)/255
Out[36]: array([0.        , 0.24705882, 0.49803922, 0.74901961, 1.        ])

That is a subtle difference, thanks for tracking it down! I think the reason we used the approach that we did, and use int, is because it makes it easier to work with qualitative colormaps when you give n_colors. (not entirely sure, I wrote that part of the code years ago in a previous library)

So, a question for you: I can definitely understand wanting to keep dependencies to the absolute minimum. So, would you like me to update this PR slightly to keep the current behavior for named colormaps that you already bundle, remove cmap from setup.py and fallback to cmap only in the case that a string name is unrecognized? That would still allow you to support custom colormaps using all the previously discussed syntax, but the user would have to opt-in to that behavior. Thoughts?

Since cmap only depends on numpy I'm fine with keeping it in, if there are issues down the road I would rather vendor it in, but I hope you're able to keep producing all the cool things you've been doing in the imaging ecosystem! :)

I like that this will now enable us to do things like line.cmap = ["blue", "green", "yellow"] to create custom arbitrary colormaps. Speaking of which, would you be interested in implementing that? No worries if you don't have time, I can easily do it in another PR 😄

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Dec 8, 2023

Copy link
Copy Markdown
Member

One more thing, does the cmap lib allow centering diverging colormaps arbitrarily?

For example if the following values exist and you want to center the seismic colormap around 0, instead of the middle value here which would be -2?

[-6, -5, -4, -3, -2, -1, 0, 1, 2]
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tlambert03
Merge branch 'main' into cmap
9307706
@tlambert03

tlambert03 commented Dec 8, 2023

Copy link
Copy Markdown
Contributor Author

I like that this will now enable us to do things like line.cmap = ["blue", "green", "yellow"] to create custom arbitrary colormaps.

I just changed examples/notebooks/lines_cmap.ipynb to the following code:

plot.graphics[0].cmap = ["blue", "green", "yellow", "#FA499E", (0, 0.2, 0.99)]

and it seemed to work just fine:

Screenshot 2023-12-08 at 10 47 32 AM

... was there something else you were expecting would be needed?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Dec 8, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Ah that's nice when two libraries work together without extra work, maybe speaks to the design of both 😄 .

Does the list of colors also work with the line collection and image example? If that works I will merge, thanks a lot! :D

I'm curious what your thoughts are on this part of our API, our goal was make it easier than and more intuitive than other libraries

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tlambert03

tlambert03 commented Dec 8, 2023

Copy link
Copy Markdown
Contributor Author

image example:

Screenshot 2023-12-08 at 12 32 39 PM

I wasn't able to find a LineCollection example, which one should I try?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar

kushalkolar commented Dec 8, 2023

Copy link
Copy Markdown
Member

This example: https://github.com/fastplotlib/fastplotlib/blob/main/examples/desktop/line_collection/line_stack.py

If you have pyqt6 installed you can use the %gui qt hook. Otherwise you can force the glfw canvas with plot = fpl.Plot(canvas="glfw")

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tlambert03

tlambert03 commented Dec 8, 2023

Copy link
Copy Markdown
Contributor Author

thanks. Yeah that example works, but it does get more confusing due to the overloading of the argument as a colormap or list of colormaps. So, one has to be rather careful there. If I do this:

# line stack takes all the same arguments as line collection and behaves similarly
cmaps = ["jet"] * len(data)
cmaps[-2:] = ["cubehelix", ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]]
plot.add_line_stack(data, cmap=cmaps)

then it works and I see this:
Screenshot 2023-12-08 at 1 29 10 PM

... but it's rather easy to get into trouble there

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tlambert03
remove colormaps
f289f8d
@kushalkolar

kushalkolar commented Dec 12, 2023

Copy link
Copy Markdown
Member

Yes you are right, because then this will raise:

plot.add_line_stack(data, cmap=["red", "blue", "green"])`

But if a line collection is already created, then this will work:

plot.graphics[0].cmap = ["red", "blue", "green"]
File ~/repos/fastplotlib/fastplotlib/graphics/line_collection.py:125, in LineCollection.__init__(self, data, z_position, thickness, colors, alpha, cmap, cmap_values, name, metadata, *args, **kwargs)
    123 elif isinstance(cmap, (tuple, list)):
    124     if len(cmap) != len(data):
--> 125         raise ValueError(
    126             "cmap argument must be a single cmap or a list of cmaps "
    127             "with the same length as the data"
    128         )
    129     single_color = False
    130 else:

ValueError: cmap argument must be a single cmap or a list of cmaps with the same length as the data

Question: We could enforce that the cmap kwarg should represent a single cmap. If the user wants to pass a list of cmaps we make a new kwarg called cmaps?

After the line collection has been created, this still works to change cmaps of individual lines:

plot.graphics[0][2:5].cmap = ["blue", "yellow", "green"]
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tlambert03

tlambert03 commented Dec 12, 2023

Copy link
Copy Markdown
Contributor Author

Question: We could enforce that the cmap kwarg should represent a single cmap. If the user wants to pass a list of cmaps we make a new kwarg called cmaps?

I can see arguments for and against. (notably, it's a breaking change). With the appropriate type checking and exception messages, it should be possible to keep a single cmap argument, but you just need to be careful about the inspection of the object and provide clear help/feedback

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@almarklein almarklein mentioned this pull request Mar 13, 2024
A bit of black #433
Merged
2 tasks done
@kushalkolar

kushalkolar commented Mar 20, 2024

Copy link
Copy Markdown
Member

Question: We could enforce that the cmap kwarg should represent a single cmap. If the user wants to pass a list of cmaps we make a new kwarg called cmaps?

I can see arguments for and against. (notably, it's a breaking change). With the appropriate type checking and exception messages, it should be possible to keep a single cmap argument, but you just need to be careful about the inspection of the object and provide clear help/feedback

Hi, sorry for the late reply, been slow getting back into this after the winter holidays!

I think we can allow the following types of use for the cmap argument in LineCollection:

  1. If it is a str of a valid cmap name, ex. jet, then it is handled how it currently is; first line would be dark blue, last line would be red.
  2. If it is a list of str check if it is possible to make a cmap from it using your library (so this should be a list of valid color names). If not go to possiblity (3) below.
  3. If it is a list of str with the same length as the number of lines, then check to make sure every str in the list is a valid cmap and each individual line uses this cmap across the length of the line.
  4. If it is a list of list, if len(outerlist) == n_lines, check that each sublist can be made into a cmap from your library and use this to color each individual line.

I think this should cover all the cases? 😄

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kushalkolar kushalkolar mentioned this pull request Mar 29, 2024
release v0.2.0 #458
Closed
11 tasks done
@kushalkolar
kushalkolar requested a review from clewis7 as a code owner June 4, 2024 16:53
@kushalkolar kushalkolar mentioned this pull request Jun 19, 2024
release v0.3.0 #534
Closed
1 of 4 tasks
@kushalkolar
Merge branch 'main' into cmap
01cab8e
@kushalkolar
kushalkolar changed the base branch from main to cmap-intermediate July 31, 2024 05:24
@kushalkolar
kushalkolar merged commit 1c92d97 into fastplotlib:cmap-intermediate Jul 31, 2024
kushalkolar added a commit that referenced this pull request Jul 31, 2024
@kushalkolar @tlambert03
use cmap library for colormaps (#390) (#574)
85337ba
* use cmap library for colormaps (#390)

* example with cmap

* add to deps

* fix shape

* use full map

* remove break

* undo changes to screenshots

* fix parse

* remove diffs

* remove x.py

* minimize diff

* add docstring

* remove colormaps

---------

Co-authored-by: Kushal Kolar <[email protected]>

* fix pygfx docs move

* black

---------

Co-authored-by: Talley Lambert <[email protected]>
kushalkolar added a commit that referenced this pull request Aug 28, 2024
@tlambert03 @kushalkolar
use cmap library for colormaps (#390)
e479be4
* example with cmap

* add to deps

* fix shape

* use full map

* remove break

* undo changes to screenshots

* fix parse

* remove diffs

* remove x.py

* minimize diff

* add docstring

* remove colormaps

---------

Co-authored-by: Kushal Kolar <[email protected]>
@kushalkolar kushalkolar mentioned this pull request Aug 30, 2024
consider cmap library? #387
Closed
kushalkolar added a commit that referenced this pull request Sep 29, 2024
@kushalkolar @tlambert03
start imgui implementation (#571)
ab5b787
* ndarray.ptp -> np.ptp for numpy v2

* use cmap library for colormaps (#390)

* example with cmap

* add to deps

* fix shape

* use full map

* remove break

* undo changes to screenshots

* fix parse

* remove diffs

* remove x.py

* minimize diff

* add docstring

* remove colormaps

---------

Co-authored-by: Kushal Kolar <[email protected]>

* fix pygfx docs move

* black

* start imgui implementation

* right click menu, hard-code toolbar height

* happy with right click menu

* black

* remove old id counter global

* cmap picker menu working, going to use cmap next to get textures working

* remove unused texture sampler

* black

* use selectable instead of menu_item

* bug and filter out wheel events too

* sort cmaps by category

* imgui imagewidget sliders working

* reset vmin vmax

* image widget with imgui done

* image widget video example

* better organization of kwargs for EdgeWindow

* add custom imgui with imagewidget example

* remove old stuff from subplot

* canvas kwargs to set initial size

* test examples works with imgui, but image widget sliders cut off for some reason

* screenshot tests work with imgui

* reset viewports when EdgeWindows added

* no more output contexts in Figure

* no more output contexts :D

* cleanup imagewidget.show()

* rename standard right click menu

* update examples

* docstrings

* better edge window

* simplify example

* cleanup

* more cleanup

* modify for docs

* modify API docs

* docstrings

* docstrings

* add UI To docs

* docs

* add UI to docs, more

* UI section in docs gallery

* docs gallery dir in conf

* add imgui-bundle to setup.py

* black

* bugfix

* use cmap library for colormaps (#390)

* example with cmap

* add to deps

* fix shape

* use full map

* remove break

* undo changes to screenshots

* fix parse

* remove diffs

* remove x.py

* minimize diff

* add docstring

* remove colormaps

---------

Co-authored-by: Kushal Kolar <[email protected]>

* fix pygfx docs move

* black

* start imgui implementation

* right click menu, hard-code toolbar height

* happy with right click menu

* black

* remove old id counter global

* cmap picker menu working, going to use cmap next to get textures working

* remove unused texture sampler

* black

* use selectable instead of menu_item

* bug and filter out wheel events too

* sort cmaps by category

* imgui imagewidget sliders working

* reset vmin vmax

* image widget with imgui done

* image widget video example

* better organization of kwargs for EdgeWindow

* add custom imgui with imagewidget example

* remove old stuff from subplot

* canvas kwargs to set initial size

* test examples works with imgui, but image widget sliders cut off for some reason

* screenshot tests work with imgui

* reset viewports when EdgeWindows added

* no more output contexts in Figure

* no more output contexts :D

* cleanup imagewidget.show()

* rename standard right click menu

* update examples

* docstrings

* better edge window

* simplify example

* cleanup

* more cleanup

* modify for docs

* modify API docs

* docstrings

* docstrings

* add UI To docs

* docs

* add UI to docs, more

* UI section in docs gallery

* docs gallery dir in conf

* add imgui-bundle to setup.py

* black

* bugfix

* basic imgui example

* finish basic custom imgui example

* start with zero noise so screenshots always match

* reset button

* comments

* plain Figure.get_pygfx_render_area()

* add get_pygfx_render_area() to basic Figure

* option to use basic Figure even if imgui installed

* image widget examples in regular examples

* black, cleanup

* image widget event when index changes

* imgui toolbar can be hidden

* black

* more black

* update api docs

* doc

* comments iw imgui sliders

* comment

* fix

* comments

* black

* update iw test nb w.r.t. imgui changes

* add iw dir to tests

* api docs

* edit api docs stuff

* readme to iw examples for docs

* docs conf.py

* stuff to make sure gui examples render in docs

* image[pyav] for docs

* fix iw movie example

* move stuff in docstring

* black

* smaller vid example for iw

* delete other heatmap examples for now

* smaller heatmap

* very small heatmap

* new screenshots with imgui

* add imgui-bundle to desktop tests

* are selectors causing OOM issues with docs

* actually bring back guis

* remove selectors

* remove misc also

* settable texture limit for 2D textures, texture test with smaller RAM footprint

* heatmap with wgpu limits set

* for examples gallery limit must be set in docs conf.py

* set texture limit for examples tests

* wgpu limits set in conftest.py

* fix linked controllers change with imgui

* autouse texture limit setup for pytest session

* correct way to set wgpu limits for pytest session

* can we now get away with phree github actions

* random seed so test screenshot looks the same

* update heatmap and iw videos test screenshots

* remove heatmap nb, add note in heatmap example

* add back selector examples

* remove linear selectors example see if docs build

* only lines for linear selector example

* separate example for image selector to see if it doesn't overrun RAM

* use real image for linear seletor

* figuring out wtf is wrong with image linear selctor on rtd

* remove zoom, IDK know anymore, wtf is up with rtd

* idk wtf is going on, makes no senze, just going to show code and not render image linear selector example for no

* bring back misc examples

* heavily subsample cockatoo vid because sphinx gallery has a memory leak :/

* iw video examples play

* add imagewidget grid to docs gallery

* proper imgui render for docs

* add subsampled iw video screenshots

* add image widget grid example

* tweak lorenz example

* added the wrong screenshot

* bring back linear selector image example

* update examples

* update setup.py

* I a comma

* slider tweaks

* update user guide

* update doc for image widget example

* fix guide

* update guide images

* other update docs

---------

Co-authored-by: Talley Lambert <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@kushalkolar kushalkolar kushalkolar requested changes
@clewis7 clewis7 Awaiting requested review from clewis7

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

consider cmap library?

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@tlambert03 @kushalkolar
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.