mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	Fix Smoothing configuration (#1476)
* Fix Smoothing out of sync when saving * Only force Smoothing for new devices * Re-Add Max/Min Brightness titles * UI - Fix: Correctly lookup current Instance Name in case instance IDs are not in order * Fix/Update AtmoOrb Firmware images
This commit is contained in:
		@@ -15,7 +15,7 @@
 | 
			
		||||
#include <FastLED.h>
 | 
			
		||||
 | 
			
		||||
#define NUM_LEDS 24 // Number of leds
 | 
			
		||||
#define DATA_PIN 7 // Data pin for leds (the default pin 7 might correspond to pin 13 on some boards)
 | 
			
		||||
#define DATA_PIN D7 // Data pin for leds (the default pin 7 might correspond to pin 13 on some boards)
 | 
			
		||||
#define SERIAL_DEBUG 0 // Serial debugging (0=Off, 1=On)
 | 
			
		||||
 | 
			
		||||
#define ID 1 // Id of this lamp
 | 
			
		||||
@@ -348,7 +348,7 @@ void identify()
 | 
			
		||||
  {
 | 
			
		||||
    FastLED.showColor(CRGB::LemonChiffon);
 | 
			
		||||
    delay(500);
 | 
			
		||||
    FastLED.showColor(CRGB::Black);   
 | 
			
		||||
    FastLED.showColor(CRGB::Black);
 | 
			
		||||
    delay(500);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										313
									
								
								assets/firmware/particle/photon/AtmoOrb_UDP.ino
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								assets/firmware/particle/photon/AtmoOrb_UDP.ino
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,313 @@
 | 
			
		||||
#include <FastLED.h>
 | 
			
		||||
FASTLED_USING_NAMESPACE;
 | 
			
		||||
 | 
			
		||||
SYSTEM_THREAD(ENABLED);
 | 
			
		||||
 | 
			
		||||
#if FASTLED_VERSION < 3001000
 | 
			
		||||
#error "Requires FastLED 3.1 or later; check github for latest code."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// WiFi
 | 
			
		||||
#define timeout 30000
 | 
			
		||||
#define reconnect_delay 5000
 | 
			
		||||
 | 
			
		||||
// UDP
 | 
			
		||||
#define SERVER_PORT 49692
 | 
			
		||||
#define DISCOVERY_PORT 49692
 | 
			
		||||
UDP client;
 | 
			
		||||
IPAddress multicastIP(239, 15, 18, 2);
 | 
			
		||||
 | 
			
		||||
// ORB
 | 
			
		||||
unsigned int orbID = 1;
 | 
			
		||||
 | 
			
		||||
#define SERIAL_DEBUG 0 // Serial debugging (0=Off, 1=On)
 | 
			
		||||
 | 
			
		||||
// LED
 | 
			
		||||
#define DATA_PIN    6
 | 
			
		||||
#define NUM_LEDS    24
 | 
			
		||||
CRGB leds[NUM_LEDS];
 | 
			
		||||
 | 
			
		||||
// UDP
 | 
			
		||||
#define BUFFER_SIZE  8 // 5 + 3 channels for 1 LED
 | 
			
		||||
#define BUFFER_SIZE_DISCOVERY 5
 | 
			
		||||
#define TIMEOUT_MS   500
 | 
			
		||||
uint8_t buffer[BUFFER_SIZE];
 | 
			
		||||
uint8_t bufferDiscovery[BUFFER_SIZE_DISCOVERY];
 | 
			
		||||
unsigned long lastWiFiCheck = 0;
 | 
			
		||||
 | 
			
		||||
// SMOOTHING
 | 
			
		||||
#define SMOOTH_STEPS 50 // Steps to take for smoothing colors
 | 
			
		||||
#define SMOOTH_DELAY 4 // Delay between smoothing steps
 | 
			
		||||
#define SMOOTH_BLOCK 0 // Block incoming colors while smoothing
 | 
			
		||||
 | 
			
		||||
byte nextColor[3];
 | 
			
		||||
byte prevColor[3];
 | 
			
		||||
byte currentColor[3];
 | 
			
		||||
byte smoothStep = SMOOTH_STEPS;
 | 
			
		||||
unsigned long smoothMillis;
 | 
			
		||||
 | 
			
		||||
// CUSTOM COLOR CORRECTIONS
 | 
			
		||||
#define RED_CORRECTION 255
 | 
			
		||||
#define GREEN_CORRECTION 255
 | 
			
		||||
#define BLUE_CORRECTION 255
 | 
			
		||||
#include "Particle.h"
 | 
			
		||||
 | 
			
		||||
void setup()
 | 
			
		||||
{
 | 
			
		||||
     // Leds - choose one correction method
 | 
			
		||||
     // 1 - Custom color correction
 | 
			
		||||
    FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS).setCorrection(CRGB(RED_CORRECTION, GREEN_CORRECTION, BLUE_CORRECTION));
 | 
			
		||||
    
 | 
			
		||||
    // Set color
 | 
			
		||||
    //setColor(40, 21, 0);
 | 
			
		||||
    
 | 
			
		||||
    // Uncomment the below lines to dim the single built-in led to 2%
 | 
			
		||||
    ::RGB.control(true);
 | 
			
		||||
    ::RGB.brightness(2);
 | 
			
		||||
    ::RGB.control(false);
 | 
			
		||||
    
 | 
			
		||||
    // WiFi
 | 
			
		||||
    lastWiFiCheck = millis();
 | 
			
		||||
    initWiFi();
 | 
			
		||||
 | 
			
		||||
    // 2 - FastLED predefined color correction
 | 
			
		||||
    //FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS).setCorrection(TypicalSMD5050);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void initWiFi()
 | 
			
		||||
{
 | 
			
		||||
    // Delays added UDP client creation, required for WiFi reconnects as takes a bit for resources to be full available
 | 
			
		||||
    
 | 
			
		||||
    // Wait for WiFi connection
 | 
			
		||||
    delay(500);
 | 
			
		||||
    waitFor(WiFi.ready, timeout);
 | 
			
		||||
    delay(reconnect_delay);
 | 
			
		||||
    
 | 
			
		||||
    // Multicast UDP
 | 
			
		||||
    if(WiFi.ready())
 | 
			
		||||
    {   
 | 
			
		||||
        #if SERIAL_DEBUG == 1
 | 
			
		||||
            Serial.println("");
 | 
			
		||||
            Serial.print(F("Connected to "));
 | 
			
		||||
            Serial.println(WiFi.SSID());
 | 
			
		||||
            Serial.print(F("IP address: "));
 | 
			
		||||
            Serial.println(WiFi.localIP());
 | 
			
		||||
        #endif
 | 
			
		||||
 | 
			
		||||
        client.begin(SERVER_PORT);
 | 
			
		||||
        delay(reconnect_delay);
 | 
			
		||||
        client.joinMulticast(multicastIP);
 | 
			
		||||
 | 
			
		||||
        #if SERIAL_DEBUG == 1
 | 
			
		||||
            Serial.print(F("Listening to Multicast at "));
 | 
			
		||||
            Serial.print(multicastIP);
 | 
			
		||||
            Serial.print(F(":"));
 | 
			
		||||
            Serial.println(SERVER_PORT);
 | 
			
		||||
        #endif
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void loop(){
 | 
			
		||||
    if (Network.listening())
 | 
			
		||||
    {
 | 
			
		||||
        // If we are in listening mode (blinking dark blue), don't
 | 
			
		||||
        // output by USB serial, because it can conflict with
 | 
			
		||||
        // serial commands.
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if(WiFi.ready() == false)    {
 | 
			
		||||
        #if SERIAL_DEBUG == 1
 | 
			
		||||
            Serial.print(F("Lost connection to "));
 | 
			
		||||
            Serial.print(WiFi.SSID());
 | 
			
		||||
            Serial.println(F("."));
 | 
			
		||||
            Serial.println(F("Trying to reconnect."));
 | 
			
		||||
        #endif
 | 
			
		||||
 | 
			
		||||
        initWiFi();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    int packetSize = client.parsePacket();
 | 
			
		||||
    
 | 
			
		||||
    if(packetSize == BUFFER_SIZE){
 | 
			
		||||
 | 
			
		||||
        #if SERIAL_DEBUG == 1
 | 
			
		||||
            Serial.print(F("Packet size: "));
 | 
			
		||||
            Serial.println(packetSize);
 | 
			
		||||
        #endif
 | 
			
		||||
        client.read(buffer, BUFFER_SIZE);
 | 
			
		||||
        //client.flush();
 | 
			
		||||
 | 
			
		||||
        #if SERIAL_DEBUG == 1
 | 
			
		||||
            Serial.print(F("UDP Packet from "));
 | 
			
		||||
            Serial.println(client.remoteIP());
 | 
			
		||||
            for (int i = 0; i < BUFFER_SIZE; i++)
 | 
			
		||||
            {
 | 
			
		||||
                Serial.print(buffer[i]);
 | 
			
		||||
                Serial.print(F(" "));
 | 
			
		||||
            }
 | 
			
		||||
            Serial.println("");
 | 
			
		||||
        #endif
 | 
			
		||||
        unsigned int i = 0;
 | 
			
		||||
        
 | 
			
		||||
        // Look for 0xC0FFEE
 | 
			
		||||
        if(buffer[i++] == 0xC0 && buffer[i++] == 0xFF && buffer[i++] == 0xEE)
 | 
			
		||||
        {
 | 
			
		||||
            byte commandOptions = buffer[i++];
 | 
			
		||||
            byte rcvOrbID = buffer[i++];
 | 
			
		||||
            
 | 
			
		||||
            byte red =  buffer[i++];
 | 
			
		||||
            byte green =  buffer[i++];
 | 
			
		||||
            byte blue =  buffer[i++];
 | 
			
		||||
            
 | 
			
		||||
            // Command options
 | 
			
		||||
            // 1 = force off
 | 
			
		||||
            // 2 = use lamp smoothing and validate by Orb ID
 | 
			
		||||
            // 4 = validate by Orb ID
 | 
			
		||||
            // 8 = discovery
 | 
			
		||||
            // 9 = light-up Orb to identify by Orb ID
 | 
			
		||||
            if(commandOptions == 1)
 | 
			
		||||
            {
 | 
			
		||||
                // Orb ID 0 = turn off all lights
 | 
			
		||||
                // Otherwise turn off selectively
 | 
			
		||||
                if(rcvOrbID == 0 || rcvOrbID == orbID)
 | 
			
		||||
                {
 | 
			
		||||
                    smoothStep = SMOOTH_STEPS;
 | 
			
		||||
                    forceLedsOFF();
 | 
			
		||||
                }
 | 
			
		||||
				
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            else if(commandOptions == 2)
 | 
			
		||||
            {
 | 
			
		||||
                if(rcvOrbID != orbID)
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                setSmoothColor(red, green, blue);
 | 
			
		||||
            }
 | 
			
		||||
            else if(commandOptions == 4)
 | 
			
		||||
            {
 | 
			
		||||
                if(rcvOrbID != orbID)
 | 
			
		||||
                {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                smoothStep = SMOOTH_STEPS;
 | 
			
		||||
                setColor(red, green, blue);
 | 
			
		||||
				        setSmoothColor(red, green, blue);
 | 
			
		||||
				
 | 
			
		||||
				        return;
 | 
			
		||||
            }
 | 
			
		||||
            else if(commandOptions == 8)
 | 
			
		||||
            {
 | 
			
		||||
                #if SERIAL_DEBUG == 1
 | 
			
		||||
                  Serial.print(F("Announce myself. OrbID: "));
 | 
			
		||||
                  Serial.println(orbID);
 | 
			
		||||
                #endif
 | 
			
		||||
                // Respond to remote IP address with Orb ID
 | 
			
		||||
                IPAddress remoteIP = client.remoteIP();
 | 
			
		||||
                bufferDiscovery[0] = orbID;
 | 
			
		||||
                
 | 
			
		||||
                client.sendPacket(bufferDiscovery, BUFFER_SIZE_DISCOVERY, remoteIP, DISCOVERY_PORT);
 | 
			
		||||
                
 | 
			
		||||
                // Clear buffer
 | 
			
		||||
                memset(bufferDiscovery, 0, sizeof(bufferDiscovery));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            else if(commandOptions == 9)
 | 
			
		||||
            {
 | 
			
		||||
                if(rcvOrbID == 0 || rcvOrbID == orbID)
 | 
			
		||||
                {
 | 
			
		||||
                    #if SERIAL_DEBUG == 1
 | 
			
		||||
                      Serial.print(F("Identify myself. OrbID: "));
 | 
			
		||||
                      Serial.println(orbID);
 | 
			
		||||
                    #endif
 | 
			
		||||
                    identify();
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
            }            
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
    }else if(packetSize > 0){
 | 
			
		||||
        // Got malformed packet
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (smoothStep < SMOOTH_STEPS && millis() >= (smoothMillis + (SMOOTH_DELAY * (smoothStep + 1))))
 | 
			
		||||
    { 
 | 
			
		||||
        smoothColor();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set color
 | 
			
		||||
void setColor(byte red, byte green, byte blue)
 | 
			
		||||
{
 | 
			
		||||
    for (byte i = 0; i < NUM_LEDS; i++)
 | 
			
		||||
    {
 | 
			
		||||
        leds[i] = CRGB(red, green, blue); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    FastLED.show();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Set a new color to smooth to
 | 
			
		||||
void setSmoothColor(byte red, byte green, byte blue)
 | 
			
		||||
{
 | 
			
		||||
    if (smoothStep == SMOOTH_STEPS || SMOOTH_BLOCK == 0)
 | 
			
		||||
    {
 | 
			
		||||
        if (nextColor[0] == red && nextColor[1] == green && nextColor[2] == blue)
 | 
			
		||||
        {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        prevColor[0] = currentColor[0];
 | 
			
		||||
        prevColor[1] = currentColor[1];
 | 
			
		||||
        prevColor[2] = currentColor[2];
 | 
			
		||||
        
 | 
			
		||||
        nextColor[0] = red;
 | 
			
		||||
        nextColor[1] = green;
 | 
			
		||||
        nextColor[2] = blue;
 | 
			
		||||
        
 | 
			
		||||
        smoothMillis = millis();
 | 
			
		||||
        smoothStep = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Display one step to the next color
 | 
			
		||||
void smoothColor()
 | 
			
		||||
{
 | 
			
		||||
    smoothStep++;
 | 
			
		||||
    currentColor[0] = prevColor[0] + (((nextColor[0] - prevColor[0]) * smoothStep) / SMOOTH_STEPS);
 | 
			
		||||
    currentColor[1] = prevColor[1] + (((nextColor[1] - prevColor[1]) * smoothStep) / SMOOTH_STEPS);
 | 
			
		||||
    currentColor[2] = prevColor[2] + (((nextColor[2] - prevColor[2]) * smoothStep) / SMOOTH_STEPS);
 | 
			
		||||
    
 | 
			
		||||
    setColor(currentColor[0], currentColor[1], currentColor[2]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Force all leds OFF
 | 
			
		||||
void forceLedsOFF()
 | 
			
		||||
{
 | 
			
		||||
    setColor(0,0,0);
 | 
			
		||||
    clearSmoothColors();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Clear smooth color byte arrays
 | 
			
		||||
void clearSmoothColors()
 | 
			
		||||
{
 | 
			
		||||
    memset(prevColor, 0, sizeof(prevColor));
 | 
			
		||||
    memset(currentColor, 0, sizeof(nextColor));
 | 
			
		||||
    memset(nextColor, 0, sizeof(nextColor));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void identify()
 | 
			
		||||
{
 | 
			
		||||
  for (byte i = 0; i < 3; i++)
 | 
			
		||||
  {
 | 
			
		||||
    FastLED.showColor(CRGB::LemonChiffon);
 | 
			
		||||
    delay(500);
 | 
			
		||||
    FastLED.showColor(CRGB::Black);
 | 
			
		||||
    delay(500);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -546,6 +546,8 @@
 | 
			
		||||
    "edt_dev_spec_baudrate_title": "Baudrate",
 | 
			
		||||
    "edt_dev_spec_blackLightsTimeout_title": "Signal detection timeout on black",
 | 
			
		||||
    "edt_dev_spec_brightnessFactor_title": "Brightness factor",
 | 
			
		||||
    "edt_dev_spec_brightnessMax_title": "Brightness maximum",
 | 
			
		||||
    "edt_dev_spec_brightnessMin_title": "Brightness minimum",
 | 
			
		||||
    "edt_dev_spec_brightnessOverwrite_title": "Overwrite brightness",
 | 
			
		||||
    "edt_dev_spec_brightnessThreshold_title": "Signal detection brightness minimum",
 | 
			
		||||
    "edt_dev_spec_brightness_title": "Brightness",
 | 
			
		||||
 
 | 
			
		||||
@@ -1631,7 +1631,10 @@ function saveLedConfig(genDefLayout = false) {
 | 
			
		||||
    case "cololight":
 | 
			
		||||
 | 
			
		||||
      var host = conf_editor.getEditor("root.specificOptions.host").getValue();
 | 
			
		||||
      result.smoothing = { enable: false };
 | 
			
		||||
      if (window.serverConfig.device.type !== ledType) {
 | 
			
		||||
        //smoothing off, if new device
 | 
			
		||||
        result.smoothing = { enable: false };
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (genDefLayout === true) {
 | 
			
		||||
 | 
			
		||||
@@ -1667,7 +1670,11 @@ function saveLedConfig(genDefLayout = false) {
 | 
			
		||||
 | 
			
		||||
    case "nanoleaf":
 | 
			
		||||
    case "wled":
 | 
			
		||||
      result.smoothing = { enable: false };
 | 
			
		||||
    case "yeelight":
 | 
			
		||||
      if (window.serverConfig.device.type !== ledType) {
 | 
			
		||||
        //smoothing off, if new device
 | 
			
		||||
        result.smoothing = { enable: false };
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    case "adalight":
 | 
			
		||||
    case "atmo":
 | 
			
		||||
 
 | 
			
		||||
@@ -171,7 +171,7 @@ function initLanguageSelection() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function updateUiOnInstance(inst) {
 | 
			
		||||
  $("#active_instance_friendly_name").text(window.serverInfo.instance[inst].friendly_name);
 | 
			
		||||
  $("#active_instance_friendly_name").text(getInstanceNameByIndex(inst));
 | 
			
		||||
  if (window.serverInfo.instance.filter(entry => entry.running).length > 1) {
 | 
			
		||||
    $('#btn_hypinstanceswitch').toggle(true);
 | 
			
		||||
    $('#active_instance_dropdown').prop('disabled', false);
 | 
			
		||||
 
 | 
			
		||||
@@ -1126,15 +1126,19 @@ function beginWizardHue() {
 | 
			
		||||
      d.useEntertainmentAPI = false;
 | 
			
		||||
      d.hardwareLedCount = finalLightIds.length;
 | 
			
		||||
      d.verbose = false;
 | 
			
		||||
      //smoothing off
 | 
			
		||||
      sc.smoothing.enable = false;
 | 
			
		||||
      if (window.serverConfig.device.type !== d.type) {
 | 
			
		||||
        //smoothing off, if new device
 | 
			
		||||
        sc.smoothing = { enable: false };
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (hueType == 'philipshueentertainment') {
 | 
			
		||||
      d.useEntertainmentAPI = true;
 | 
			
		||||
      d.hardwareLedCount = groupLights.length;
 | 
			
		||||
      //smoothing on
 | 
			
		||||
      sc.smoothing.enable = true;
 | 
			
		||||
      if (window.serverConfig.device.type !== d.type) {
 | 
			
		||||
        //smoothing on, if new device
 | 
			
		||||
        sc.smoothing = { enable: true };
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    window.serverConfig.device = d;
 | 
			
		||||
@@ -1430,6 +1434,8 @@ function beginWizardYeelight() {
 | 
			
		||||
    window.serverConfig.leds = yeelightLedConfig;
 | 
			
		||||
 | 
			
		||||
    //LED device config
 | 
			
		||||
    var currentDeviceType = window.serverConfig.device.type;
 | 
			
		||||
 | 
			
		||||
    //Start with a clean configuration
 | 
			
		||||
    var d = {};
 | 
			
		||||
 | 
			
		||||
@@ -1454,9 +1460,10 @@ function beginWizardYeelight() {
 | 
			
		||||
 | 
			
		||||
    window.serverConfig.device = d;
 | 
			
		||||
 | 
			
		||||
    //smoothing off
 | 
			
		||||
    if (!(window.serverConfig.smoothing == null))
 | 
			
		||||
      window.serverConfig.smoothing.enable = false;
 | 
			
		||||
    if (currentDeviceType !== d.type) {
 | 
			
		||||
      //smoothing off, if new device
 | 
			
		||||
      window.serverConfig.smoothing = { enable: false };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    requestWriteConfig(window.serverConfig, true);
 | 
			
		||||
    resetWizard();
 | 
			
		||||
 
 | 
			
		||||
@@ -113,10 +113,8 @@ void LinearColorSmoothing::handleSettingsUpdate(settings::type type, const QJson
 | 
			
		||||
	if (type == settings::type::SMOOTHING)
 | 
			
		||||
	{
 | 
			
		||||
		QJsonObject obj = config.object();
 | 
			
		||||
		if (enabled() != obj["enable"].toBool(true))
 | 
			
		||||
		{
 | 
			
		||||
			setEnable(obj["enable"].toBool(true));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		setEnable(obj["enable"].toBool(_enabled));
 | 
			
		||||
 | 
			
		||||
		SmoothingCfg cfg(false,
 | 
			
		||||
						  static_cast<int64_t>(obj[SETTINGS_KEY_SETTLING_TIME].toInt(DEFAULT_SETTLINGTIME)),
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user