-
-
Notifications
You must be signed in to change notification settings - Fork 11.7k
[Model] Initial support for BLIP-2 #5920
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
251 commits
Select commit
Hold shift + click to select a range
df2aa19
Move dummy data generation to input registry
DarkLight1337 c72d2b3
Update docs
DarkLight1337 d8c6488
Rename `process_input` to `map_input`
DarkLight1337 f18de48
Reorder arguments
DarkLight1337 653537d
Apply input processor
DarkLight1337 a2f5a3c
Remove `VisionLanguageConfig` from input mapper
DarkLight1337 378ad80
Fix bad use of `functools.partial`
DarkLight1337 7aa3778
Use default input processor
DarkLight1337 c774168
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 532f863
Fix wrong arguments
DarkLight1337 080d40c
Use pillow image instead of tensor to avoid bypassing the processor b…
DarkLight1337 662693a
Update interface of dummy data factory and input processor
DarkLight1337 9bc5fcc
Use `InputContext` to handle checked type cast of config types
DarkLight1337 911cac7
Add input processor for injecting image tokens; fix docs
DarkLight1337 a38b347
Add new documentation pages
DarkLight1337 29c3bb3
Fix LLaVA-NeXT input processor and cleanup code
DarkLight1337 9cfbcce
Fix LLaVA-NeXT input processor and cleanup code
DarkLight1337 7bb6cbf
Add sanity check
DarkLight1337 ccf49c4
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 3482d32
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 8ea8468
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 be3d64f
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 2ff5be6
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 8e2ff86
Update LLaVA-NeXT
DarkLight1337 553f684
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 b134dfc
Update name
DarkLight1337 1efa480
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 1a08444
Update LLaVA-NeXT
DarkLight1337 7e33706
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 cfc31fd
Merge branch 'upstream' into mm-image-tokenizer-2
DarkLight1337 3fb622c
Remove `MULTIMODAL` convenience property as it was causing some (impo…
DarkLight1337 da85ab2
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 383bea1
Update docs
DarkLight1337 80a09f2
Remove double processing of image tokens
DarkLight1337 6a70e4f
Add docs
DarkLight1337 8322ecb
Add docs
DarkLight1337 52a0116
Add docs
DarkLight1337 c1733dd
Add docs
DarkLight1337 b7a8683
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 9fb5e72
Remove more instances of double processing; update docs
DarkLight1337 25f9949
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 03c7e65
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 3932b3f
Remove xfail
DarkLight1337 7fa877a
Fix missing image token in OpenAI API serving
DarkLight1337 092e550
Fix LLaVA-NeXT test
DarkLight1337 7a19862
Remove duplicate processing in async engine
DarkLight1337 fd7d954
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 49dac3e
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 b2c6832
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 0104218
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 18cc7e0
Set up dummy data factory for phi3v
DarkLight1337 2291617
Move dummy data factories to model files
DarkLight1337 adf5503
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 e5a94e4
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 9b0386d
Move input processors to model files
DarkLight1337 4e656e7
Set up input processor for phi3v
DarkLight1337 fecf1f0
Fix wrong feature size
DarkLight1337 086e0fe
Fix wrong feature size
DarkLight1337 8c26a18
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 81522fe
Fix wrong feature size
DarkLight1337 c036b86
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 f75e1ab
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 b24e8d9
Update validation
DarkLight1337 8569d35
Fix image feature calculation for phi3v
DarkLight1337 bfa5aa9
Remove redundant code
DarkLight1337 dc34121
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 07e695d
Apply isort
DarkLight1337 8a43a77
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 825401d
Apply yapf
DarkLight1337 4a0d4d1
Reduce `max_tokens` so that test still passes
DarkLight1337 8d22fe0
Fix vllm to hf output (+ rename)
DarkLight1337 2e1ee2f
Fix wrong arguments
DarkLight1337 7229b07
Move `DummyImageDataFactories` into CLIP model file
DarkLight1337 17800fd
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 50f994b
Move `input_processor_for_clip` into CLIP
DarkLight1337 838aa9b
Remove some magic numbers
DarkLight1337 e7a5564
Test multiscale inputs for LLaVA-NeXT
DarkLight1337 36e8001
Handle multiscale inputs (different number of patches per batch) in L…
DarkLight1337 39e6d42
Fix wrong feature size
DarkLight1337 0d7f18f
Apply formatter
DarkLight1337 8e5dc7c
Merge branch 'upstream' into mm-image-tokenizer-2
DarkLight1337 d9a4150
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 6849236
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 6d02491
Revert max_tokens
DarkLight1337 76ddea4
Add more tests for input mapper
DarkLight1337 4b20e66
Sanity check: Also test multiscale inputs for LLaVA-1.5
DarkLight1337 784af1a
Do not auto-convert image dtype to model's dtype
DarkLight1337 8e5fb12
Update prompts
DarkLight1337 4b947ad
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 e7397ee
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 865be7a
Fix mapper tests w.r.t. dtype change
DarkLight1337 9e82a26
Clarify docs and add todo
DarkLight1337 46391de
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 a4733f9
Remove TODO since vision config will be removed soon
DarkLight1337 6b19e6c
Expand docs
DarkLight1337 be326f2
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 f451668
Add ref
DarkLight1337 5c0c8cf
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 3d7b795
Update docs
DarkLight1337 1abb8a7
Add docs
DarkLight1337 428d420
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 698830f
Fix name
DarkLight1337 ac9ea9a
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 334b1a9
Add `MultiModalInputs` to docs
DarkLight1337 36ab12d
Fix and add links
DarkLight1337 af01e97
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 c303421
Fix `is_multiscale` not provided anymore
DarkLight1337 0a0c0e3
Also test multiscale input for phi3v
DarkLight1337 60517a7
Revert max_tokens for phi3v as numerical error still persists
DarkLight1337 57df434
Improve error message
DarkLight1337 ffe0675
Log the full output for easier reference
DarkLight1337 c7a2a66
Update xfail to be more efficient
DarkLight1337 598e0e3
Also xfail llava test
DarkLight1337 f84d87a
Update comment
DarkLight1337 5dfb6fc
Update docs
DarkLight1337 bbeff03
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 bf3281c
modify llava_next
ywang96 56e2d3b
Update comment
DarkLight1337 d2f8c6d
Update docs
DarkLight1337 7c197d2
Use dynamic image feature size calculation
DarkLight1337 f5ffd3e
Fix phi3v not handling `image_sizes` correctly
DarkLight1337 66aad21
Apply formatter
DarkLight1337 d1c68c0
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 5f32d53
Add see also
DarkLight1337 15df4ef
Update examples prompt format
DarkLight1337 f2e4633
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 095e008
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 a6e3162
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 28922af
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 ce06541
Fix config
DarkLight1337 cdcc2d4
Fix config
DarkLight1337 4212abf
Update docs
DarkLight1337 07c08e3
Update docs
DarkLight1337 f3f5854
Fix `MultiModalInputs` not working in Python 3.8
DarkLight1337 bebf9e7
Fix `_ImageAssets` not working in Python 3.8
DarkLight1337 3f4f4bf
Merge branch 'upstream' into blip-2
DarkLight1337 e948275
Inital impl. BLIP-2
DarkLight1337 06d2339
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 fc83d0c
Update BLIP-2 using new API
DarkLight1337 eb33485
Enable test to run
DarkLight1337 d68c462
Fix input processor
DarkLight1337 b909c60
Fix wrong lm_head
DarkLight1337 9b85e60
Fix wrong output of vision tower
DarkLight1337 e864427
Fix BLIP-2 repeating output and output conversion
DarkLight1337 7e80ecc
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 487d742
Merge branch 'upstream' into mm-image-tokenizer
DarkLight1337 36f72b6
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 e354d2b
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 43350b8
update example
ywang96 57791de
update doc
ywang96 b2b1e11
Merge branch 'mm-image-tokenizer' into mm-image-tokenizer-2
DarkLight1337 5757821
Apply formatter
DarkLight1337 f36e099
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 fbc5f70
Update docs
DarkLight1337 dbeee10
Support `eos_token_id` from `config.json`
DarkLight1337 161585a
Add `trust_remote_code`
DarkLight1337 261dc71
Merge branch 'eos-from-config' into blip-2
DarkLight1337 36de6f4
Use updated EOS token detection code
DarkLight1337 4292ccb
Merge branch 'upstream' into mm-image-tokenizer-2
DarkLight1337 6a24360
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 5d23a96
Apply formatter
DarkLight1337 9c91649
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 78d2e10
Apply formatter
DarkLight1337 78064e0
Fix OpenAI server not working for phi3v
DarkLight1337 4cb809c
Preemptively handle upcoming models
DarkLight1337 754e238
Add more models
DarkLight1337 9edb53c
Update feature size for dummy data
DarkLight1337 2795b16
Use a less strict check
DarkLight1337 86ffd60
Fix phi3v test
DarkLight1337 f339dd1
Update default length as the dummy image feature size is increased
DarkLight1337 59a7a4c
Raise full error if output is completely different
DarkLight1337 62952e1
Fix phi3v not using input processor
DarkLight1337 49f39d6
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 5810335
Update BLIP-2 test according to merged changes
DarkLight1337 0ce3ecb
Move size factors outside
DarkLight1337 379b99a
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 b43e8c3
Apply formatter
DarkLight1337 ac25521
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 9e2e69a
Move size factors outside
DarkLight1337 44dec19
Implement BLIPVisionModel in vLLM
DarkLight1337 9023794
Fix some outputs not being checked
DarkLight1337 453e144
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 3da4a00
Fix some outputs not being checked
DarkLight1337 fc5549c
Merge branch 'upstream' into mm-image-tokenizer-2
DarkLight1337 f6c8061
Also test no image
DarkLight1337 e4f99e6
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 191c671
Also test no image
DarkLight1337 15cc847
Merge branch 'upstream' into mm-image-tokenizer-2
DarkLight1337 235c8a9
Batch by size factors
DarkLight1337 b98d924
Factor out xfail code
DarkLight1337 a3eb4fe
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 90c60f3
Apply merge changes to BLIP-2 test
DarkLight1337 2c2558b
Fix unused args
DarkLight1337 b0d868c
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 ec28eca
Check logprobs instead of xfailing
DarkLight1337 5a337f5
Merge branch 'upstream' into mm-image-tokenizer-2
DarkLight1337 05db877
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 213e1e4
Apply merge changes to BLIP-2 tests
DarkLight1337 2eb3490
Fix different scales not being in the same batch
DarkLight1337 9b42589
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 e671249
Apply merge changes to BLIP-2 tests
DarkLight1337 6301a52
Apply suggestions from code review
DarkLight1337 14f10fc
Add link
DarkLight1337 7c335c3
Use `self.multi_modal_projector` directly
DarkLight1337 33c860e
Allow users to send image token formatted prompt directly
DarkLight1337 e03bc57
Factor out the code for placeholder token IDs
DarkLight1337 a9da5cf
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 b270ac3
Remove `-rx` flag
DarkLight1337 36095e1
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 3161221
Fix distributed tests
DarkLight1337 85d108a
Fix string mismatch warning
DarkLight1337 d648e32
Relax phi3v test; add TODO for llava tests
DarkLight1337 37fa0e7
Merge branch 'mm-image-tokenizer-2' into blip-2
DarkLight1337 2e4a833
Merge branch 'upstream' into blip-2
DarkLight1337 d685c28
Add missing space
DarkLight1337 46bf209
Update test
DarkLight1337 74606ef
Update docs
DarkLight1337 04e5adc
Apply formatter
DarkLight1337 fc59a9e
Remove workaround - it's not needed anymore
DarkLight1337 8dc69b2
Merge branch 'upstream' into blip-2
DarkLight1337 49b9c55
Update BLIP-2 and normalize validation/docs
DarkLight1337 d6fe0f7
Update docs
DarkLight1337 685d463
Update validation
DarkLight1337 b00757c
Merge branch 'upstream' into blip-2
DarkLight1337 49e18b1
Merge branch 'upstream' into blip-2
DarkLight1337 85c65da
Add entry to supported models
DarkLight1337 13324d9
Add vertical space
DarkLight1337 3ba9b54
Fix extra BOS
DarkLight1337 6d3537e
Fix extra space
DarkLight1337 9eca3fd
Update `output_len` calculation in HF runner
DarkLight1337 c7077f8
ruff
DarkLight1337 4c82329
Merge branch 'upstream' into blip-2
DarkLight1337 da7600f
Remove "boardwalk" asset
DarkLight1337 1e4349c
Merge branch 'upstream' into blip-2
DarkLight1337 03b27d9
Format
DarkLight1337 eec28e6
Merge branch 'upstream' into blip-2
DarkLight1337 28cc937
yapf
DarkLight1337 3203ded
Merge branch 'upstream' into blip-2
DarkLight1337 a24d633
Rename
DarkLight1337 f41b468
Fix merge
DarkLight1337 92047c4
Format
DarkLight1337 d3d1814
Fix type error
DarkLight1337 356ec29
Update models with recent refactors
DarkLight1337 3dbf3fc
Remove unused attribute
DarkLight1337 47d777c
Remove unused comment
DarkLight1337 eba25fb
Merge branch 'upstream' into blip-2
ywang96 cb32e09
update
ywang96 a0d45bb
Merge branch 'upstream' into blip-2
ywang96 11f9223
Add chat template for BLIP-2
DarkLight1337 388bae4
Merge branch 'upstream' into blip-2
DarkLight1337 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| {%- for message in messages -%} | ||
| {%- if message['role'] == 'user' -%} | ||
| {{- 'Question: ' + message['content'] + ' ' -}} | ||
| {%- elif message['role'] == 'assistant' -%} | ||
| {{- 'Answer: ' + message['content'] + ' ' -}} | ||
| {%- endif -%} | ||
| {%- endfor -%} | ||
|
|
||
| {%- if add_generation_prompt -%} | ||
| {{- 'Answer:' -}} | ||
| {% endif %} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| from typing import List, Optional, Tuple | ||
|
|
||
| import pytest | ||
| from transformers import AutoTokenizer | ||
|
|
||
| from vllm.multimodal.utils import rescale_image_size | ||
| from vllm.sequence import SampleLogprobs | ||
|
|
||
| from ..conftest import IMAGE_ASSETS | ||
| from .utils import check_logprobs_close | ||
|
|
||
| pytestmark = pytest.mark.vlm | ||
|
|
||
| HF_IMAGE_PROMPTS = IMAGE_ASSETS.prompts({ | ||
| "stop_sign": | ||
| "Question: What's the content of the image? Answer:", | ||
| "cherry_blossom": | ||
| "Question: What is the season? Answer:", | ||
| }) | ||
|
|
||
|
|
||
| def vllm_to_hf_output(vllm_output: Tuple[List[int], str, | ||
| Optional[SampleLogprobs]], | ||
| model: str): | ||
| """Sanitize vllm output to be comparable with hf output.""" | ||
| _, output_str, out_logprobs = vllm_output | ||
|
|
||
| hf_output_str = output_str + "\n" | ||
|
|
||
| tokenizer = AutoTokenizer.from_pretrained(model) | ||
| hf_output_ids = tokenizer.encode(hf_output_str) | ||
| assert hf_output_ids[0] == tokenizer.bos_token_id | ||
| hf_output_ids = hf_output_ids[1:] | ||
|
|
||
| return hf_output_ids, hf_output_str, out_logprobs | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("model", ["Salesforce/blip2-opt-2.7b"]) | ||
| @pytest.mark.parametrize( | ||
| "size_factors", | ||
| [ | ||
| # No image | ||
| [], | ||
| # Single-scale | ||
| [1.0], | ||
| # Single-scale, batched | ||
| [1.0, 1.0, 1.0], | ||
| # Multi-scale | ||
| [0.25, 0.5, 1.0], | ||
| ], | ||
| ) | ||
| @pytest.mark.parametrize("dtype", ["half"]) | ||
| @pytest.mark.parametrize("max_tokens", [128]) | ||
| @pytest.mark.parametrize("num_logprobs", [5]) | ||
| def test_models(hf_runner, vllm_runner, image_assets, model, size_factors, | ||
| dtype: str, max_tokens: int, num_logprobs: int) -> None: | ||
| """Inference result should be the same between hf and vllm. | ||
|
|
||
| All the image fixtures for the test is under tests/images. | ||
| For huggingface runner, we provide the PIL images as input. | ||
| For vllm runner, we provide MultiModalData objects and corresponding | ||
| vision language config as input. | ||
| Note, the text input is also adjusted to abide by vllm contract. | ||
| The text output is sanitized to be able to compare with hf. | ||
| """ | ||
| images = [asset.pil_image for asset in image_assets] | ||
|
|
||
| inputs_per_image = [( | ||
| [prompt for _ in size_factors], | ||
| [rescale_image_size(image, factor) for factor in size_factors], | ||
| ) for image, prompt in zip(images, HF_IMAGE_PROMPTS)] | ||
|
|
||
| # max_model_len should be greater than image_feature_size | ||
| with vllm_runner(model, dtype=dtype, enforce_eager=True) as vllm_model: | ||
| vllm_outputs_per_image = [ | ||
| vllm_model.generate_greedy_logprobs(prompts, | ||
| max_tokens, | ||
| num_logprobs=num_logprobs, | ||
| images=images) | ||
| for prompts, images in inputs_per_image | ||
| ] | ||
|
|
||
| with hf_runner(model, dtype=dtype, is_vision_model=True) as hf_model: | ||
| hf_outputs_per_image = [ | ||
| hf_model.generate_greedy_logprobs_limit(prompts, | ||
| max_tokens, | ||
| num_logprobs=num_logprobs, | ||
| images=images) | ||
| for prompts, images in inputs_per_image | ||
| ] | ||
|
|
||
| for hf_outputs, vllm_outputs in zip(hf_outputs_per_image, | ||
| vllm_outputs_per_image): | ||
| check_logprobs_close( | ||
| outputs_0_lst=hf_outputs, | ||
| outputs_1_lst=[ | ||
| vllm_to_hf_output(vllm_output, model) | ||
| for vllm_output in vllm_outputs | ||
| ], | ||
| name_0="hf", | ||
| name_1="vllm", | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.