array_random

Description
This is a function I wrote a long time ago for one of my first games, and ended up dropping it on nearly every project I make. It lets you pick an element at random from an array. It can either return the value or the index, and you can specify weights if you do not want a uniform selection. The weights can also be specified with arbitrary numbers, and the function will normalize those weights to add up to 100%. Finally, all arguments are optional, so if you don't specify anything it is equivalent to choose(0,1), if you only specify the array it will select an element at random uniformly (i.e. equal weights) and if you only specify a weights array it will assume the array is a consecutive index array ([0,1, 2, ...]) up to the size of the weights array.
Uses
A lot, but it's super useful for dropping random loot, procedural generation of levels, procedural generation of enemy waves depending on level difficulty, etc. Check the write-up I made on random number generation if needed here. Page 3 specifically talks about this.
Examples
Say we have a possible items drop array for a monster loot or treasure chest (I'll specify them a strings for exemplification purposes, probably these would be structs or object references on an actual game):
self.items = ["Coins", "Shield", "Sword", "Gem"];
Then:

var _item = array_random(self.items, [0.4, 0.3, 0.2, 0.1], false); - Returns a random item from the items array (which should have four items). The first item is weighed at 40% chance, the second at 30% and so on.
var _item = array_random(self.items, [40, 30, 20, 10], false); - Exactly the same as before. The function will normalize the weights. This allows to think on loot chances as proportional to one another (for example, something with weight 66 will have double chance than something with weight 33, regardless of what the total sum of weights are).
var _item_idx = array_random(self.items, [0.4, 0.3, 0.2, 0.1], true); - Same as before, but returns the index of the selected item instead.
var _item_idx = array_random(self.items); - Returns a random item from the items array, with equal weights. Equivalent to self.items[irandom(array_length(self.items-1))].

Also:

var _item_idx = array_random(,[0.4, 0.3, 0.2, 0.1]) - Returns a random number from [0, 1, 2, 3], with the specified weights.
var _item_idx = array_random() - Returns a random number from [0, 1], uniformly. Equivalent to choose(0,1).

Current code
The current code works good. I'm sure we can clean it up a little and make it a bit more robust to be included in this package, but it's a good start.
///@function			array_random(array=[], probabilities=[], return_index=false)
///@description			selects an item or index from the array with the specified probability array
///@param				{array}		_array			the array that holds the values to select from
///@param				{array}		_probabilities	the array that holds the corresponding probabilities
///@param				{bool}		_return_index	if true return selected index; if false [default] return value from _array
///@return				{any}		the randomly selected item or index
function array_random(_array = [], _probabilities = [], _return_index = false) {
	// Specifying an empty _array means [0,1,...] the same size as _probs array
	// Specifying an empty _probs means considering uniform probabilities the same size as _array
	// If both are empty, generate a Bernoulli with p=0.5 (fair coin toss)
	var _arr = _array;
	var _probs = _probabilities;
	var _n = array_length(_arr);
	var _p = array_length(_probs);
	if (!is_array(_arr) && !is_array(_probs) || _n == 0 && _p == 0) {
		return choose(0,1);
	}
	else {
		if (array_length(_arr) == 0) 	for (var _i=0; _i<_p; _i++)		array_push(_arr, _i);
		if (array_length(_probs) == 0)	for (var _i=0; _i<_n; _i++)		array_push(_probs, 1/_n);
		_n = array_length(_arr);
		_p = array_length(_probs);
		if (_n != _p) throw("The value array and the probability array must be of the same size");
		var _neg = false;
		_i=0;
		while (_i<_p && !_neg) {
			if (_probs[_i] < 0)		_neg = true;
			else _i++;
		}
		if (_neg) throw("The probability array cannot have negative values");

		// Normalize probability array
		var _sum = 0;
		for (var _i=0; _i<_p; _i++)		_sum += _probs[_i];
		if (abs(1-_sum) != 1)	for (var _i=0; _i<_p; _i++)		_probs[_i] /= _sum;

		// Generate continuous random variable and compare against CDF
		var _u = random(1);

		var _i = 0;
		var _cdf = _probs[0];
		while (_u > _cdf && _i<_p) {
			_i++;
			_cdf += _probs[_i];
		}

		if (_return_index)	return _i;
		else return _arr[_i];
	}
}

Hmmm... I think there are a bunch of different functionalities to be had here, and they might be better split up instead of getting into overloads overload.
One potential derived function would be choose_weight_index(weight1, weight2, ...)
It's pretty similar to your array_random() with no _array given and _return_index being set to true. Because let's face it, if you set _return_index to true, _array argument doesn't matter anyway.
So something like choose_weight_index(0.6, 0.3, 0.1) would choose index 0 with 60% chance, index 1 with 30% chance and index 2 with 10% chance. It wouldn't even need to do any special division-based normalisation; instead, the random would be calculated from the sum in the first place, like so:
function choose_weight_index(_weights) {
    var _weights_sum = 0;
    for (var i = 0; i < argument_count; i++) {
        _weights_sum += argument[i];
    }
    var _value = random(_weights_sum);
    for (var i = 0; i < argument_count; i++) {
        if (_value < argument[i])
            return i;
        else
            _value -= argument[i];
    }
}

Then, for an array based variant, it could be something like choose_weight_index_ext, in a similar way e.g. string_ext(format, args) is an array-based version of string(format, ...args)
Then another derived function could be choose_weighted(item1, weight1, item2, weight2, ...)
So something like choose_weighted("hp_potion", 0.6, "mp_potion", 0.3, "iron_sword", 0.1) would choose HP potion with 60% chance, MP potion with 30% chance and Iron Sword with 10% chance.
I don't yet use arrays here, because I don't want to encourage creating new arrays too much, and array literals create a new array every time the code is run. Still, if someone wants to match up the items array with weights, they might use something like choose_weighted_ext(items, weights), I guess?
Then, for weightless choosing, we would instead apply the function Dragonite mentioned on GMC:
function array_random_element(array) {
    return array[irandom(array_length(array) - 1)];
}

Except I guess I would call it array_get_random(_array) and make an array_delete_random(_array) counterpart. As the name implies, the latter would remove a random element from an array and return its value; I've found myself using it on multiple occasions.
Quite a few design decisions to be had here for sure, but in general I think some extra functions for randomly picking elements (especially picking elements from arrays) would be quite welcome. ^^

I suggest array_pop_random instead of array_delete_random. It feels more straightforward if you're already familiar with the built-in array_pop and I don't think deleting an index from an array implies that the value will be returned, ds_priorities are the only structures that return deleted data.
I know you said you don't want too many new arrays going around, but I think I'd prefer if a function like choose_weight_index took an array of weights as an argument, instead of a bunch of reals. Passing more than a couple numbers in as arguments would be pretty clumsy, and for many of the proposed use cases I can see myself wanting to pick from dozens or hundreds of options, not just three or four.

Made a separate issue #26 focusing on the uniform array_get_random/array_pop_random or whatever else we call them. This feature will stay open for discussion and voting about more advanced array randomisation features (mostly the weighed choice).

There's also this implementation: https://yal.cc/gamemaker-weighted-choose/


undefined local variable or method 'gpio_init'

I was trying to get numlock working as described on the numlock, capslock, and scroll lock page on the wiki, when I discovered that the example code does not work
Output:
`===============================================
PRK Firmware 0.9.22 (20230904 revision 568e003)
PICORUBY_MSC: MSC_FLASH
prk-conf: ::
STATS 124856/211968
Init Keyboard
Init GPIO
NoMethodError
undefined local variable or method 'gpio_init' for Object
Task stopped!
`
my keymap.rb is attached and seems to work as expected when lines 10-17 are omitted
I expect it's a require that I'm missing? I've truid require "gpio" but that didn't help. I'm not familiar with ruby but i'll poke around the repo and update if I can figure anything else
keymap.txt

Methods like gpio_init no longer work in recent releases.
You can see the current GPIO's API here: https://github.com/mruby/microcontroller-peripheral-interface-guide/blob/main/mruby_io_GPIO_en.md


[crazy feature] Ignore spells/abilities not found yet

Hello Timo,
Not sure if this is even possible or something useful but I can see a niche for it.
I wonder if spells that are not recognized by the editor (they do not show up with syntax highlight) because the character haven't learned it yet it, can be skipped on the sequence or on any of the macro boxes.
Example of uses:

People try to use a macro and it locks up because they forgot to put the talents right and therefore the ability called off in the macro can't be found. So the macro skips it to partially use the macro.
Players can use the same macro of a high level character on a low level, because the spells get skipped if not found. The macro can growth with the character.

Not sure if this is the current behavior, but I have read in the past where some people have forgotten to put the right talents and the macro was not working for them because of it.
A ramification for the example 1, it could be a feature of highlighting in red the spell or a tooltip message saying that "the spell or ability is not in the spellbook check talents or lvl" something like that.

Here is another person with the same issue I believe:
https://wowlazymacros.com/t/gnome-sequencer-for-idiots-ask-and-you-will-be-answered/1359/435

This is look but don’t touch space.
Once you are in combat GSE can do nothing to alter what it sends WoW to execute in any way.  This is unfortunately Garbage in, Garbage Out.
In most cases if the player can’t cast the spell it will skip.  If however it’s a castsequence the castsequence will hang.  In either case by the time it’s come to execution it’s too late.  Those changes needed to be dealt with in the editor and if the player didn’t, they didn’t.  They just fed garbage in.
TimothyLuke

On 30 Jul 2019, at 12:46 am, Luis Cestou<EMAIL_ADDRESS>wrote:
Hello Timo,
Not sure if this is even possible or something useful but I can see a niche for it.
I wonder if spells that are not recognized by the editor (they do not show up with syntax highlight) because the character haven't learned it yet it, can be skipped on the sequence or on any of the macro boxes.
Example of uses:
People try to use a macro and it locks up because they forgot to put the talents right and therefore the ability called off in the macro can't be found. So the macro skips it to partially use the macro.
Players can use the same macro of a high level character on a low level, because the spells get skipped if not found. The macro can growth with the character.
Not sure if this is the current behavior, but I have read in the past where some people have forgotten to put the right talents and the macro was not working for them because of it.
A ramification for the example 1, it could be a feature of highlighting in red the spell or a tooltip message saying that "the spell or ability is not in the spellbook check talents or lvl" something like that.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.

Following on the feedback is making it red.  This doesn’t mean it won’t work, it just mean it’s not recognised.  Wow also doesn’t give me the fine control to be able to interpret what is in the box until it is saved.  Hence not being able to put up a tooltip when you hover over that red spell.
TimothyLuke

On 30 Jul 2019, at 12:46 am, Luis Cestou<EMAIL_ADDRESS>wrote:
Hello Timo,
Not sure if this is even possible or something useful but I can see a niche for it.
I wonder if spells that are not recognized by the editor (they do not show up with syntax highlight) because the character haven't learned it yet it, can be skipped on the sequence or on any of the macro boxes.
Example of uses:
People try to use a macro and it locks up because they forgot to put the talents right and therefore the ability called off in the macro can't be found. So the macro skips it to partially use the macro.
Players can use the same macro of a high level character on a low level, because the spells get skipped if not found. The macro can growth with the character.
Not sure if this is the current behavior, but I have read in the past where some people have forgotten to put the right talents and the macro was not working for them because of it.
A ramification for the example 1, it could be a feature of highlighting in red the spell or a tooltip message saying that "the spell or ability is not in the spellbook check talents or lvl" something like that.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.

Ok, cool.
Thanks Tim!
PS: Did you ever received the logos?


Release/0.3.0

What
Add authentication to private endpoints using dp-authorization library. Also retrieve headers for calculating csv dimension offset for finding observation metadata as well as:

fix self link to use observation API url instead of using the dataset API url retrieved from version document.
add zebedee checker to healthcheck for publishing instance
handle errors from dataset API
update unit tests
update dependencies to use latest library versions, also use dp-net instead of deprecated dp-rchttp

How to review

Sanity check changes
Check unit tests pass.

Who can review
Anyone

There is a race condition with service.Run() - a fix is being implemented, so will refrain from merging until fix has been merged onto this release branch


"Spanțov" is listed in the drop-down menu

Description:
"Spanțov" is listed in the drop-down menu alongside its corresponding county and commune, according to the law
Precondition:
The website is up an running.

Step 1
Type "Spanțov" in the search bar.

Expected results
The location is listed in the drop-down menu as "Comuna Spanțov, CĂLĂRAȘI".


Undefined method `axis' for XPath:Module

My test for a URL is passing as:
page.should have_link('Popular')

but when I change it to:
page.should have_link('Popular', :href => '/')

it fails saying:

Failure/Error: page.should have_link('Popular', :href => '/')
     NoMethodError:
       undefined method `axis' for XPath:Module

I'm using Capybara with Capybara-Webkit driver from thoughtbot.. I also have :js => true turned on for this spec, am I doing something wrong?

I just realized that this only happens when I have in my gemfile:
gem 'capybara', :git => 'git://github.com/jnicklas/capybara.git'
when I use
gem 'capybara' the error does not come up.. maybe this is a known issue, should have checked that earlier.

This happens because you are using the latest capybara, but not the latest XPath. You need both.

Thank you, much appreciations.


clustermesh511 upgrade testing

this PR is for testing the new CI workflow being introduced in https://github.com/cilium/cilium/pull/27232 against the extended clustermesh feature PR
This should not be merged and will be closed after testing.

/test

/ci-multicluster

passing run: https://github.com/cilium/cilium/actions/runs/5956377171


Updates on registry endpoints related doc

This PR updates registry related doc for

Deprecate purview configs under feature_registry in docs, replace with endpoint config
Update notebook not to use deprecated registry config

Let's don't deprecate for now as there are a few customers using the existing way (connecting to purview directly from Feathr Client).

I add back legacy configs and add deprecate soon in description to note new users.


document abortForAuth only has function during data gathering phase

The abortForAuth API can only be used during the data gathering phase, but we do not mention this in the docs.

Fixed.


Prefer normal namespace with meta over unique namespace

This should fix all item entries issues (when adding new items to Dragonfly)

Not sure what this changes as it's such a massive file, but I'll merge it, assuming it's tested.


Title: "Improve Codebase Clarity and Immutability by Utilizing 'const' Declarations"

I've noticed that our codebase could benefit from enhanced clarity and immutability. By incorporating 'const' declarations where applicable, we can make our code easier to understand and maintain. This change will also help prevent unintended modifications to variables, reducing the risk of bugs and improving code reliability. I propose refactoring the codebase to leverage 'const' declarations extensively. This will require a thorough review and implementation across relevant code files

i would like to contribute to this issue... kindly assign me


Setting tabIndex for jexcel_textarea field

Hi,
Please set the tabIndex attribute value "-1" for the "jexcel_textarea" field, so that on pressing "tab" key focus will not go to that field.
Example: obj.textarea.tabIndex="-1";

It has been done. It will be in the repo in the next few hours.


Interval doesn't seem to do anything

I'm using react-moment in a web page, and while it displays correctly with no errors, it is not updating. Here is the code I'm using:
`import React, { Component } from 'react';
import Moment from 'react-moment';
export default class Clock extends Component {
render(){
    const displayTime = new Date();
    return(
        <Moment interval={1000} format={this.props.format}>
            {displayTime}
        </Moment>
    );
}

}
`
This component is called by the following line from another page:
<Clock fromat="yyyy MMM dd HH:mm:ss"/>
I'm using the latest version of react from npm.

I'm trying to use it with React Native, also running in to the same issue.

I confirm this bug :see_no_evil:

Interval doesnt work

I solved it by using regular moment and creating my own interval.
setInterval( () => {       this.setState({         curTime : moment().format('HH:mm A'),         curDate : moment().format('dddd Do MMMM')       })     },1000)


Is there a way to terminate vllm.LLM and release the GPU memory

After below code, is there an api(maybe like llm.terminate) to kill llm and release the GPU memory?
from vllm import LLM, SamplingParams

prompts = [
    "Hello, my name is",
    "The president of the United States is",
    "The capital of France is",
    "The future of AI is",
]
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
outputs = llm.generate(prompts, sampling_params)

Even after executing the code above, the GPU memory is not freed with the latest vllm built from source. Any recommendations?

Even after executing the code above, the GPU memory is not freed with the latest vllm built from source. Any recommendations?即使在执行上述代码后，GPU 内存也不会使用从源代码构建的最新 vllm 释放。有什么建议吗？

same question.

Are there any updates on this? the above code does not work for me either

+1

I find that we need to explicitly run "del llm.llm_engine.driver_worker" to release in when using a single worker.
Can anybody explain why this is the case?

+1

I find that we need to explicitly run "del llm.llm_engine.driver_worker" to release in when using a single worker. Can anybody explain why this is the case?

I tried the above code block and also this line "del llm.llm_engine.driver_worker". Both failed for me.

But I managed, with the following code, to terminate the vllm.LLM(), release the GPU memory, and shut down ray in convenience for using vllm.LLM() for the next model. After this, I succeeded in using vllm.LLM() again for the next model.
        #llm is a vllm.LLM object
        import gc
        import torch
        from vllm.model_executor.parallel_utils.parallel_state import destroy_model_parallel

        destroy_model_parallel()
        #del a vllm.executor.ray_gpu_executor.RayGPUExecutor object
        del llm.llm_engine.model_executor
        del llm
        gc.collect()
        torch.cuda.empty_cache()
        import ray
        ray.shutdown()

Anyway, even if it works, it is just a temporary solution and this issue still needs fixing.

I find that we need to explicitly run "del llm.llm_engine.driver_worker" to release in when using a single worker. Can anybody explain why this is the case?

I tried the above code block and also this line "del llm.llm_engine.driver_worker". Both failed for me.
But I managed, with the following code, to terminate the vllm.LLM(), release the GPU memory, and shut down ray in convenience for using vllm.LLM() for the next model. After this, I succeeded in using vllm.LLM() again for the next model.
        #llm is a vllm.LLM object
        import gc
        import torch
        from vllm.model_executor.parallel_utils.parallel_state import destroy_model_parallel

        destroy_model_parallel()
        #del a vllm.executor.ray_gpu_executor.RayGPUExecutor object
        del llm.llm_engine.model_executor
        del llm
        gc.collect()
        torch.cuda.empty_cache()
        import ray
        ray.shutdown()

Anyway, even if it works, it is just a temporary solution and this issue still needs fixing.

update:
the following code would work better, without the possible dead lock warning.
        #llm is a vllm.LLM object
        import gc
        import torch
        from vllm.model_executor.parallel_utils.parallel_state import destroy_model_parallel
        import os

        #avoid huggingface/tokenizers process dead lock
        os.environ["TOKENIZERS_PARALLELISM"] = "false"
        destroy_model_parallel()
        #del a vllm.executor.ray_gpu_executor.RayGPUExecutor object
        del llm.llm_engine.model_executor
        del llm
        gc.collect()
        torch.cuda.empty_cache()
        import ray
        ray.shutdown()

In the latest version of vLLM destroy_model_parallel has moved to vllm.distributed.parallel_state. The objects you have to delete have also changed:
from vllm.distributed.parallel_state import destroy_model_parallel
...
destroy_model_parallel()
del llm.llm_engine.model_executor.driver_worker
del llm # Isn't necessary for releasing memory, but why not
gc.collect()
torch.cuda.empty_cache()

In the latest version of vLLM destroy_model_parallel has moved to vllm.distributed.parallel_state. The objects you have to delete have also changed:
from vllm.distributed.parallel_state import destroy_model_parallel
...
destroy_model_parallel()
del llm.llm_engine.model_executor.driver_worker
del llm # Isn't necessary for releasing memory, but why not
gc.collect()
torch.cuda.empty_cache()

thx a lot

vLLM seems to hang to the first allocated LLM() instance. It does not hang to later instances. Maybe that helps with diagnosing the issue?
from vllm import LLM

def show_memory_usage():
    import torch.cuda
    import torch.distributed
    import gc

    print(f"cuda memory: {torch.cuda.memory_allocated()//1024//1024}MB")
    gc.collect()
    # torch.distributed.destroy_process_group()
    torch.cuda.empty_cache()
    print(f"  --> after gc: {torch.cuda.memory_allocated()//1024//1024}MB")

def gc_problem():
    show_memory_usage()
    print("loading llm0")
    llm0 = LLM(model="facebook/opt-125m", num_gpu_blocks_override=180)
    del llm0
    show_memory_usage()

    print("loading llm1")
    llm1 = LLM(model="facebook/opt-125m", num_gpu_blocks_override=500)
    del llm1
    show_memory_usage()

    print("loading llm2")
    llm2 = LLM(model="facebook/opt-125m", num_gpu_blocks_override=600)
    del llm2
    show_memory_usage()

gc_problem()

root@c09a058c2d5b:/workspaces/aici/py/vllm# python tests/core/block/e2e/gc_problem.py |grep -v INFO
cuda memory: 0MB
  --> after gc: 0MB
loading llm0
cuda memory: 368MB
  --> after gc: 368MB
loading llm1
cuda memory: 912MB
  --> after gc: 368MB
loading llm2
[rank0]:[W CUDAGraph.cpp:145] Warning: Waiting for pending NCCL work to finish before starting graph capture. (function operator())
cuda memory: 961MB
  --> after gc: 368MB
root@c09a058c2d5b:/workspaces/aici/py/vllm#

The llm1 consumes more than llm0 but you can see that the allocated memory stays at llm0 level.

Tried this including ray.shutdown() but the memory is not released on my end, any other suggestion?

could try the "del llm.llm_engine.model_executor" in the following code instead:

update: the following code would work better, without the possible dead lock warning.
        #llm is a vllm.LLM object
        import gc
        import torch
        from vllm.model_executor.parallel_utils.parallel_state import destroy_model_parallel
        import os

        #avoid huggingface/tokenizers process dead lock
        os.environ["TOKENIZERS_PARALLELISM"] = "false"
        destroy_model_parallel()
        #del a vllm.executor.ray_gpu_executor.RayGPUExecutor object
        del llm.llm_engine.model_executor
        del llm
        gc.collect()
        torch.cuda.empty_cache()
        import ray
        ray.shutdown()

In the latest version of vLLM destroy_model_parallel has moved to vllm.distributed.parallel_state. The objects you have to delete have also changed:
from vllm.distributed.parallel_state import destroy_model_parallel
...
destroy_model_parallel()
del llm.llm_engine.model_executor.driver_worker
del llm # Isn't necessary for releasing memory, but why not
gc.collect()
torch.cuda.empty_cache()

We tried this in version 0.4.2, but GPU memory did not release it.

did that as well, still no change in gpu memory allocation. Not sure how to go further

Then I do not have a clue either. Meanwhile, I should add an information: the vllm version with which I succeeded with the above code was 0.4.0.post1

@zheyang0825 does adding this lines at the end make it work?
torch.distributed.destroy_process_group()

Hello ! so if I'm not wrong, no one achieved to release memory on vllm 0.4.2 yet ?

A new bug was introduced in 0.4.2, but fixed in https://github.com/vllm-project/vllm/pull/4737. Please try with that PR or as a workaround you can also install tensorizer.
This should resolve such errors at least for TP=1. For TP > 1, there may be other issues with creating a new LLM instance after deleting one in the same process.

A new bug was introduced in 0.4.2, but fixed in #4737. Please try with that PR or as a workaround you can also install tensorizer.
This should resolve such errors at least for TP=1. For TP > 1, there may be other issues with creating a new LLM instance after deleting one in the same process.

I updated vllm yesterday and still have the problem, I'm using those lines :
destroy_model_parallel()
del llm.llm_engine.model_executor.driver_worker
del llm
gc.collect()
torch.cuda.empty_cache()

This code is worked for me
vllm==0.4.0.post1
        import gc
        import ray
        from vllm.model_executor.parallel_utils.parallel_state import destroy_model_parallel

        print('service stopping ..')
        print(f"cuda memory: {torch.cuda.memory_allocated() // 1024 // 1024}MB")

        destroy_model_parallel()

        del model.llm_engine.model_executor.driver_worker
        del model

        gc.collect()
        torch.cuda.empty_cache()
        ray.shutdown()

        print(f"cuda memory: {torch.cuda.memory_allocated() // 1024 // 1024}MB")

        print("service stopped")

There should be a built-in way! We cannot keep writing code that breaks on the next minor release :(

In general it is very difficult to clean up all resources correctly, especially when we use multiple GPUs, and might be prone to deadlocks .
I would say, the most stable way to terminate vLLM is to shut down the process.

A new bug was introduced in 0.4.2, but fixed in #4737. Please try with that PR or as a workaround you can also install tensorizer.
This should resolve such errors at least for TP=1. For TP > 1, there may be other issues with creating a new LLM instance after deleting one in the same process.

I encountered this issue when TP = 8. I'm doing this in a iterative manner since I need to run the embedding model after the generative model so there are so loading / offloading. The first iteration is fine but the second iteration the instantiation of vllm ray server hangs.

In general it is very difficult to clean up all resources correctly, especially when we use multiple GPUs, and might be prone to deadlocks .
I would say, the most stable way to terminate vLLM is to shut down the process.

I understand your point. However, this feature is extremely useful for situations where you need to switch between models. For instance, reinforcement learning loops. I am writing an off-policy RL loop, requiring me to train one model (target policy) while its previous version performs inference (behavior policy). As a result, I frequently load and unload models. While I know vLLM is not intended for training, using transformers would be too slow, making my technique unviable.

I don't know if anyone can currently clear memory correctly, but in version 0.4.2, I applied the above code that failed to clear memory correctly. I can only use a slightly extreme method of creating a new process before calling and closing the process after calling to roughly solve the problem:
from multiprocessing import Process, set_start_method
set_start_method('spawn', force=True)
def vllm_texts(model_path):
    prompts=""
    sampling_params = SamplingParams(max_tokens=512)
    llm = LLM(model=model_path)
    outputs = llm.generate(prompts, sampling_params)

...
print(torch.cuda.memory_summary())
p = Process(target=vllm_texts, args=(model_path))
p.start()
p.join()
if p.is_alive():
    p.terminate()
p.close()
print(torch.cuda.memory_summary())
...

I still hope there is a way in the future to correctly and perfectly clear memory

While I am using multiple GPUs to serve a LLM (tensor_parallel_size > 1), the GPUs' memory is not released, except the first GPU (cuda:0).

In general it is very difficult to clean up all resources correctly, especially when we use multiple GPUs, and might be prone to deadlocks .
I would say, the most stable way to terminate vLLM is to shut down the process.

I understand your point. However, this feature is extremely useful for situations where you need to switch between models. For instance, reinforcement learning loops. I am writing an off-policy RL loop, requiring me to train one model (target policy) while its previous version performs inference (behavior policy). As a result, I frequently load and unload models. While I know vLLM is not intended for training, using transformers would be too slow, making my technique unviable.
Let me know if this is a feature that's wanted and the team would be interested in maintaining it. I can open a separate issue and start working on it.

Glad to see you here @cassanof and to hear that you have been using vLLM in this kind of workflow!
Given how much wanted this feature seems to be, I will bring this back to the team to discuss! If multi-gpu instance is prone to deadlocks, then perhaps we can at least start with single-gpu instances. Everyone on the maintainer team does have limited bandwidth and we have a lot of things to work on, so contributions are very welcomed as always!

I tried inferring multiple models consecutively with vLLM v0.5.2. As mentioned above, the behavior differs depending on the value of TP.

If you want to unload a model with TP=1 and then load a model with TP=1, the process described in https://github.com/vllm-project/vllm/issues/1908#issuecomment-2076870351 will work without any problems.
If you want to unload a model with TP=1 and then load a model with TP=2, or vice versa, in addition to the code above, you need to do export VLLM_WORKER_MULTIPROC_METHOD=spawn in https://github.com/vllm-project/vllm/issues/6152#issuecomment-2211709345, and run vllm.distributed.parallel_state.destroy_distributed_environment().

There is an issue where the warning message https://github.com/vllm-project/vllm/issues/6025 appears after execution.

The above does not work to unload and reload the model with TP=2. I tried ray.shutdown() but it did not work.

I use this function in a pipeline where I explain images with VLM and then summarize them with LLM. I hope that this kind of processing will be officially provided and become common.
from vllm import LLM, SamplingParams
from vllm.distributed.parallel_state import destroy_model_parallel, destroy_distributed_environment
import torch
import gc
import os

os.environ["VLLM_WORKER_MULTIPROC_METHOD"] = "spawn"

def main():
    prompts = ["Hello, my name is"]
    sampling_params = SamplingParams(temperature=0.8, top_p=0.95)

    llm = LLM(model="facebook/opt-125m", tensor_parallel_size=1)
    outputs = llm.generate(prompts, sampling_params)
    print(outputs)

    destroy_model_parallel()
    destroy_distributed_environment()
    del llm.llm_engine.model_executor
    del llm
    gc.collect()
    torch.cuda.empty_cache()

    llm = LLM(model="facebook/opt-125m", tensor_parallel_size=2)
    outputs = llm.generate(prompts, sampling_params)
    print(outputs)

if __name__ == "__main__":
    main()

I tried inferring multiple models consecutively with vLLM v0.5.2. As mentioned above, the behavior differs depending on the value of TP.

If you want to unload a model with TP=1 and then load a model with TP=1, the process described in Is there a way to terminate vllm.LLM and release the GPU memory #1908 (comment) will work without any problems.

If you want to unload a model with TP=1 and then load a model with TP=2, or vice versa, in addition to the code above, you need to do export VLLM_WORKER_MULTIPROC_METHOD=spawn in [Bug]: When tensor_parallel_size>1,  RuntimeError: Cannot re-initialize CUDA in forked subprocess. #6152 (comment), and run vllm.distributed.parallel_state.destroy_distributed_environment().

There is an issue where the warning message [Bug]: Producer process has been terminated before all shared CUDA tensors released (v 0.5.0 post1, v 0.4.3) #6025 appears after execution.

The above does not work to unload and reload the model with TP=2. I tried ray.shutdown() but it did not work.

I use this function in a pipeline where I explain images with VLM and then summarize them with LLM. I hope that this kind of processing will be officially provided and become common.
from vllm import LLM, SamplingParams
from vllm.distributed.parallel_state import destroy_model_parallel, destroy_distributed_environment
import torch
import gc
import os

os.environ["VLLM_WORKER_MULTIPROC_METHOD"] = "spawn"

def main():
    prompts = ["Hello, my name is"]
    sampling_params = SamplingParams(temperature=0.8, top_p=0.95)

    llm = LLM(model="facebook/opt-125m", tensor_parallel_size=1)
    outputs = llm.generate(prompts, sampling_params)
    print(outputs)

    destroy_model_parallel()
    destroy_distributed_environment()
    del llm.llm_engine.model_executor
    del llm
    gc.collect()
    torch.cuda.empty_cache()

    llm = LLM(model="facebook/opt-125m", tensor_parallel_size=2)
    outputs = llm.generate(prompts, sampling_params)
    print(outputs)

    destroy_model_parallel()
    destroy_distributed_environment()
    del llm.llm_engine.model_executor
    del llm
    gc.collect()
    torch.cuda.empty_cache()

if __name__ == "__main__":
    main()

It works for me.

I tried inferring multiple models consecutively with vLLM v0.5.2. As mentioned above, the behavior differs depending on the value of TP.

If you want to unload a model with TP=1 and then load a model with TP=1, the process described in Is there a way to terminate vllm.LLM and release the GPU memory #1908 (comment) will work without any problems.

If you want to unload a model with TP=1 and then load a model with TP=2, or vice versa, in addition to the code above, you need to do export VLLM_WORKER_MULTIPROC_METHOD=spawn in [Bug]: When tensor_parallel_size>1,  RuntimeError: Cannot re-initialize CUDA in forked subprocess. #6152 (comment), and run vllm.distributed.parallel_state.destroy_distributed_environment().

There is an issue where the warning message [Bug]: Producer process has been terminated before all shared CUDA tensors released (v 0.5.0 post1, v 0.4.3) #6025 appears after execution.

The above does not work to unload and reload the model with TP=2. I tried ray.shutdown() but it did not work.

I use this function in a pipeline where I explain images with VLM and then summarize them with LLM. I hope that this kind of processing will be officially provided and become common.
from vllm import LLM, SamplingParams
from vllm.distributed.parallel_state import destroy_model_parallel, destroy_distributed_environment
import torch
import gc
import os

os.environ["VLLM_WORKER_MULTIPROC_METHOD"] = "spawn"

def main():
    prompts = ["Hello, my name is"]
    sampling_params = SamplingParams(temperature=0.8, top_p=0.95)

    llm = LLM(model="facebook/opt-125m", tensor_parallel_size=1)
    outputs = llm.generate(prompts, sampling_params)
    print(outputs)

    destroy_model_parallel()
    destroy_distributed_environment()
    del llm.llm_engine.model_executor
    del llm
    gc.collect()
    torch.cuda.empty_cache()

    llm = LLM(model="facebook/opt-125m", tensor_parallel_size=2)
    outputs = llm.generate(prompts, sampling_params)
    print(outputs)

    destroy_model_parallel()
    destroy_distributed_environment()
    del llm.llm_engine.model_executor
    del llm
    gc.collect()
    torch.cuda.empty_cache()

if __name__ == "__main__":
    main()

With TP=1, I am able to unload the model without difficulty with the method described above, but the re-loading fails with a esoteric error, like:
File "/home/bhavnick/fd/workspace/vllm-api/modules/llm/generator.py", line 139, in load
    engine = AsyncLLMEngine.from_engine_args(args)
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/engine/async_llm_engine.py", line 466, in from_engine_args
    engine = cls(
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/engine/async_llm_engine.py", line 380, in __init__
    self.engine = self._init_engine(*args, **kwargs)
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/engine/async_llm_engine.py", line 547, in _init_engine
    return engine_class(*args, **kwargs)
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/engine/llm_engine.py", line 251, in __init__
    self.model_executor = executor_class(
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/executor/executor_base.py", line 47, in __init__
    self._init_executor()
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/executor/gpu_executor.py", line 35, in _init_executor
    self.driver_worker.init_device()
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/worker/worker.py", line 132, in init_device
    init_worker_distributed_environment(self.parallel_config, self.rank,
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/worker/worker.py", line 346, in init_worker_distributed_environment
    ensure_model_parallel_initialized(parallel_config.tensor_parallel_size,
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/distributed/parallel_state.py", line 920, in ensure_model_parallel_initialized
    backend = backend or torch.distributed.get_backend(
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/torch/distributed/distributed_c10d.py", line 1074, in get_backend
    return Backend(not_none(pg_store)[0])
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/torch/utils/_typing_utils.py", line 12, in not_none
    raise TypeError("Invariant encountered: value was None when it should not be")
TypeError: Invariant encountered: value was None when it should not be

I tried inferring multiple models consecutively with vLLM v0.5.2. As mentioned above, the behavior differs depending on the value of TP.

If you want to unload a model with TP=1 and then load a model with TP=1, the process described in Is there a way to terminate vllm.LLM and release the GPU memory #1908 (comment) will work without any problems.

If you want to unload a model with TP=1 and then load a model with TP=2, or vice versa, in addition to the code above, you need to do export VLLM_WORKER_MULTIPROC_METHOD=spawn in [Bug]: When tensor_parallel_size>1,  RuntimeError: Cannot re-initialize CUDA in forked subprocess. #6152 (comment), and run vllm.distributed.parallel_state.destroy_distributed_environment().

There is an issue where the warning message [Bug]: Producer process has been terminated before all shared CUDA tensors released (v 0.5.0 post1, v 0.4.3) #6025 appears after execution.

The above does not work to unload and reload the model with TP=2. I tried ray.shutdown() but it did not work.

I use this function in a pipeline where I explain images with VLM and then summarize them with LLM. I hope that this kind of processing will be officially provided and become common.
from vllm import LLM, SamplingParams
from vllm.distributed.parallel_state import destroy_model_parallel, destroy_distributed_environment
import torch
import gc
import os

os.environ["VLLM_WORKER_MULTIPROC_METHOD"] = "spawn"

def main():
    prompts = ["Hello, my name is"]
    sampling_params = SamplingParams(temperature=0.8, top_p=0.95)

    llm = LLM(model="facebook/opt-125m", tensor_parallel_size=1)
    outputs = llm.generate(prompts, sampling_params)
    print(outputs)

    destroy_model_parallel()
    destroy_distributed_environment()
    del llm.llm_engine.model_executor
    del llm
    gc.collect()
    torch.cuda.empty_cache()

    llm = LLM(model="facebook/opt-125m", tensor_parallel_size=2)
    outputs = llm.generate(prompts, sampling_params)
    print(outputs)

    destroy_model_parallel()
    destroy_distributed_environment()
    del llm.llm_engine.model_executor
    del llm
    gc.collect()
    torch.cuda.empty_cache()

if __name__ == "__main__":
    main()

With TP=1, I am able to unload the model without difficulty with the method described above, but the re-loading fails with a esoteric error, like:
File "/home/bhavnick/fd/workspace/vllm-api/modules/llm/generator.py", line 139, in load
    engine = AsyncLLMEngine.from_engine_args(args)
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/engine/async_llm_engine.py", line 466, in from_engine_args
    engine = cls(
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/engine/async_llm_engine.py", line 380, in __init__
    self.engine = self._init_engine(*args, **kwargs)
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/engine/async_llm_engine.py", line 547, in _init_engine
    return engine_class(*args, **kwargs)
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/engine/llm_engine.py", line 251, in __init__
    self.model_executor = executor_class(
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/executor/executor_base.py", line 47, in __init__
    self._init_executor()
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/executor/gpu_executor.py", line 35, in _init_executor
    self.driver_worker.init_device()
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/worker/worker.py", line 132, in init_device
    init_worker_distributed_environment(self.parallel_config, self.rank,
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/worker/worker.py", line 346, in init_worker_distributed_environment
    ensure_model_parallel_initialized(parallel_config.tensor_parallel_size,
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/vllm/distributed/parallel_state.py", line 920, in ensure_model_parallel_initialized
    backend = backend or torch.distributed.get_backend(
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/torch/distributed/distributed_c10d.py", line 1074, in get_backend
    return Backend(not_none(pg_store)[0])
  File "/home/bhavnick/fd/workspace/pyenv/vllm-api/lib/python3.10/site-packages/torch/utils/_typing_utils.py", line 12, in not_none
    raise TypeError("Invariant encountered: value was None when it should not be")
TypeError: Invariant encountered: value was None when it should not be

Some differences I can think of is I am using the AysncLLMEngine instead of the synchronous version, but the unload works just the same.

UPDATE: Works with ray at TP=2 but for some reason not with multiprocessing with either fork or spawn. Also, only unload works with ray but not reload right now.

@bhavnicksm  I can reproduce the same error you have.

When debugging, I found that when using 'spawn' the main GPU used (if using PCI_BUS) would still keep some small amount of memory allocated, indicating that the clean up is unsuccessful.
When I then check all available GPUs that have zero memory allocated and export CUDA_VISIBLE_DEVICES, I am able to progress into changing into another model until another issue hits that seemingly indicates the workers distributed state is still somewhere in memory.
  File "/home/ubuntu/vllm/vllm/engine/async_llm_engine.py", line 380, in __init__     self.engine = self._init_engine(*args, **kwargs)   File "/home/ubuntu/vllm/vllm/engine/async_llm_engine.py", line 551, in _init_engine     return engine_class(*args, **kwargs)   File "/home/ubuntu/vllm/vllm/engine/llm_engine.py", line 250, in __init__     self.model_executor = executor_class(   File "/home/ubuntu/vllm/vllm/executor/multiproc_gpu_executor.py", line 215, in __init__     super().__init__(*args, **kwargs)   File "/home/ubuntu/vllm/vllm/executor/distributed_gpu_executor.py", line 25, in __init__     super().__init__(*args, **kwargs)   File "/home/ubuntu/vllm/vllm/executor/executor_base.py", line 47, in __init__     self._init_executor()   File "/home/ubuntu/vllm/vllm/executor/multiproc_gpu_executor.py", line 137, in _init_executor     self._run_workers("init_device")   File "/home/ubuntu/vllm/vllm/executor/multiproc_gpu_executor.py", line 192, in _run_workers     driver_worker_output = driver_worker_method(*args, **kwargs)   File "/home/ubuntu/vllm/vllm/worker/worker.py", line 132, in init_device     init_worker_distributed_environment(self.parallel_config, self.rank,   File "/home/ubuntu/vllm/vllm/worker/worker.py", line 343, in init_worker_distributed_environment     init_distributed_environment(parallel_config.world_size, rank,   File "/home/ubuntu/vllm/vllm/distributed/parallel_state.py", line 874, in init_distributed_environment     assert _WORLD.world_size == torch.distributed.get_world_size(), ( AssertionError: world group already initialized with a different world **size**

Another update:
The problem is the global _WORLD variable that stays None. When overriding the backend to be 'nccl' hardcoded at vllm/distributed/parallel_state.py", line 920, in ensure_model_parallel_initialized, the whole state goes in deadlock:
    engine = AsyncLLMEngine.from_engine_args(engine_args)
  File "/home/ubuntu/vllm/vllm/engine/async_llm_engine.py", line 470, in from_engine_args
    engine = cls(
  File "/home/ubuntu/vllm/vllm/engine/async_llm_engine.py", line 380, in __init__
    self.engine = self._init_engine(*args, **kwargs)
  File "/home/ubuntu/vllm/vllm/engine/async_llm_engine.py", line 551, in _init_engine
    return engine_class(*args, **kwargs)
  File "/home/ubuntu/vllm/vllm/engine/llm_engine.py", line 250, in __init__
    self.model_executor = executor_class(
  File "/home/ubuntu/vllm/vllm/executor/multiproc_gpu_executor.py", line 215, in __init__
    super().__init__(*args, **kwargs)
  File "/home/ubuntu/vllm/vllm/executor/distributed_gpu_executor.py", line 25, in __init__
    super().__init__(*args, **kwargs)
  File "/home/ubuntu/vllm/vllm/executor/executor_base.py", line 47, in __init__
    self._init_executor()
  File "/home/ubuntu/vllm/vllm/executor/multiproc_gpu_executor.py", line 137, in _init_executor
    self._run_workers("init_device")
  File "/home/ubuntu/vllm/vllm/executor/multiproc_gpu_executor.py", line 192, in _run_workers
    driver_worker_output = driver_worker_method(*args, **kwargs)
  File "/home/ubuntu/vllm/vllm/worker/worker.py", line 132, in init_device
    init_worker_distributed_environment(self.parallel_config, self.rank,
  File "/home/ubuntu/vllm/vllm/worker/worker.py", line 346, in init_worker_distributed_environment
    ensure_model_parallel_initialized(parallel_config.tensor_parallel_size,
  File "/home/ubuntu/vllm/vllm/distributed/parallel_state.py", line 969, in ensure_model_parallel_initialized
    initialize_model_parallel(tensor_model_parallel_size,
  File "/home/ubuntu/vllm/vllm/distributed/parallel_state.py", line 931, in initialize_model_parallel
    _TP = init_model_parallel_group(group_ranks,
  File "/home/ubuntu/vllm/vllm/distributed/parallel_state.py", line 773, in init_model_parallel_group
    return GroupCoordinator(
  File "/home/ubuntu/vllm/vllm/distributed/parallel_state.py", line 154, in __init__
    self.pynccl_comm = PyNcclCommunicator(
  File "/home/ubuntu/vllm/vllm/distributed/device_communicators/pynccl.py", line 74, in __init__
    dist.broadcast(tensor, src=ranks[0], group=group)
  File "/opt/conda/envs/llm2/lib/python3.10/site-packages/torch/distributed/c10d_logger.py", line 79, in wrapper
    return func(*args, **kwargs)
  File "/opt/conda/envs/llm2/lib/python3.10/site-packages/torch/distributed/distributed_c10d.py", line 2213, in broadcast

@hammer-wang what version of vLLM are you using, which distributed backend (ray or multiprocessing) and how are you running the server?

Got it working on vllm 0.5.x
Adding these two flags to my LLM call:
distributed_executor_backend='mp'
disable_custom_all_reduce=True

and
def vllm_cleanup(llm):
    del llm.llm_engine.model_executor
    del llm
    destroy_model_parallel()
    destroy_distributed_environment()
    with contextlib.suppress(AssertionError):
        torch.distributed.destroy_process_group()
    gc.collect()
    if not is_cpu():
        torch.cuda.empty_cache()
    ray.shutdown()

using this method after llm.generate works for me

This setup works perfectly on my end when using multiple GPUs! FYI, I am using pip install vllm==0.6.3.post1:
import gc
import contextlib

import ray
import torch
from vllm import LLM, SamplingParams
from vllm.distributed.parallel_state import (
    destroy_model_parallel,
    destroy_distributed_environment,
)

llm = LLM(
        model=save_dir,
        tokenizer=model_name,
        dtype='bfloat16',
        # Acknowledgement: Benjamin Kitor
        # https://github.com/vllm-project/vllm/issues/2794
        distributed_executor_backend="mp",
        tensor_parallel_size=num_gpus_vllm,
        gpu_memory_utilization=gpu_utilization_vllm,
        # Note: We add this only to save the GPU Memories!
        max_model_len=max_model_len_vllm,
        disable_custom_all_reduce=True,
        enable_lora=False,
)

# Delete the llm object and free the memory
destroy_model_parallel()
destroy_distributed_environment()
del llm.llm_engine.model_executor
del llm
with contextlib.suppress(AssertionError):
        torch.distributed.destroy_process_group()
gc.collect()
torch.cuda.empty_cache()
ray.shutdown()
print("Successfully delete the llm pipeline and free the GPU memory.")

why is del llm.llm_engine.model_executor needed?


Binary histogram charts too small in mobile

Current behavior
on binary questions, the desktop histogram looks like this:

on mobile:

Expected/desired behavior
probably, the aspect ratio of the graph should adjust to the container's width, so that the chart stays the same height

Ready for testing on dev

Beautiful!


Can Pylance warn unused parameters like Java

As the title says,
Expecte like Java:

We can see the underline reminder, which also exists in the problem
Fact in Python:

Only the color reminder, which is really not obvious.

Pylance supports the following diagnostic rules:
reportUnusedImport - reports imports that are unreferenced
reportUnusedVariable - reports local variables that are unreferenced
reportUnusedClass - reports class that is unreferenced within the module (applies only to private classes whose names start with an underscore)
reportUnusedFunction - reports function that is unreferenced within the module (applies only to private functions whose names start with an underscore)
You can enable these diagnostic rules by updating your project settings.
{
  "python.analysis.diagnosticSeverityOverrides": {
    "reportUnusedImport": "error",
    "reportUnusedClass": "warning"
  }
}```

@erictraut
I don't know why. Recently, even though I added these two lines of reminders, I still didn't get any reminders from pylance. Is there any update from pylance? How can I get the prompt again.


Feature Request: Take alias name from zabbix item name

Would be nice, if alias is taken from zabbix item name.
Needed chekpoint (fill alias from zabbix) if it is set, grafana must take it from zabbix api, not from alias field

Implemented. See 2b2f9979335f1fffa42a831d20ceb39eadd5edd3 (develop-1.9 branch for now).
Just add new metric and alias sets by default or delete existing alias.

I'll test it tomorrow. but from your description I think it is not perfect logic, sometimes item name from zabbix can be too long, and some one would want to rename it i grafana not in zabbix, I think it must be a option

You may edit alias as you want. It will remain. Very simple logic ))

Cool it works

Yes, new features will be added in release 1.1.0 (see milestones). This is rule of semantic versioning.


Strange controls visibility with firefox

I've recently notice that on firefox, i can't see :

The play link (div.play-wrapper > div.poster-icon.play)
The volume icon on the bottom right
The fullscreen icon on the bottom right

A sample can be found here : http://www.iwilive.net/streams/view/pleneuf0

did u check if there's a css conflict that only express in firefox?

You must be right because it doesn't happens on cdn.clappr.io and neither on my other websites.

Ok i've found it : i made a wrong use of player.resize, so it didn't work fine on firefox


Update Laravel.gitignore

Reasons for making this change:
The most of Laravel developers are using dedicated/VPS servers. So it's difficult to have a Laravel project with PUBLIC path there, as apache entry point is PUBLIC_HTML.
Added PUBLIC_HTML/ some folders in gitignore

@alkhachatryan thanks!


LiOn needs a logo!

What do you think about this?

Is going to be added to Readme and Favicon with the WADL changes

#168 Added the logo to the Readme and favicon.


Read only support in o-input

Description
readonly property is not supported in o-input. Sometimes this functionality is needed so it would be useful to add it
Why Oruga need this feature
Complements the current operation of o-input, additionally the readonly property is native in the <input> tag
I can add the support, but in the contribution guide it was suggested to post it as an Issue before developing it

@netoec84 there isn't a class because you can style it with readonly attribute by CSS but if you want to add a new class prop you are welcome 😉