wget -m delete local files that are not existing anymore on the server

I use wget -m to mirror my webspace to my nas.
So far it’s working great, but I noticed that when a file on the server got deleted, it will be still there locally.

Is there any way to delete the local files that aren’t existing anymore on the server?

In case of the backup, that won’t be a problem, because after wget I zip the files with a timestamp.

I found some old forum posts online talking about this missing feature, but those are 15 years old.
Is there any possible way to do it now?

Why no local SMS provider in Laos ?

Hi

I’m looking for local bulk SMS sending provider in Laos.

but, It’s has no one provider in there.

Why is that?

Could someone e… | Read the rest of https://www.webhostingtalk.com/showthread.php?t=1839146&goto=newpost

c – Embedded IoT: local data storage (Updated)

I have made most of the review changes based on feedback I have got from here. Now I am back here for a second review to further better my code. Before posting the changes, somethings I haven’t changed are the following.

  1. I have left the print statements as-is for now. The reason for this is, at times if something goes wrong at the client site, we usually ask them to grab logs and share them with us. I still haven’t given enough thought to the mechanism to control what needs to be printed and what not.

  2. I am still in the midst of figuring out ways to further simplify the whole code from logic and structure. Especially when it comes to handling the wrap-around while reading the timestamps for data writes and reads.

  3. I still need to figure out how to make the tests work for humans. It will take some time to come up with test cases and codes. But I am going to keep that aside for now considering the amount of time I have left to complete this task.

  4. I have managed to get rid of most of the warnings. However, I still have a few warnings as shown below.
    enter image description here
    I am a bit reluctant to fix these warnings as they end up breaking the code. For instance, doing the below will get rid of the warning.

           *timestamp |= *(uint32_t*)cBucketBufHeadTmp << (8 * I);
    

But it breaks the code since now the pointer typecasted to read uint32_t and not uint8_t which is not what I intend to do. The same goes for the others.

Now coming to the code, below is the header file.

/*
 * Bucket.h
 *
 * Created: 17/12/2020 12:57:45 PM
 *  Author: Vinay Divakar
 */


#ifndef BUCKET_H_
#define BUCKET_H_

#define BUCKET_SIZE           32        // Range 10-32000 Memory in bytes allocated to bucket for edge storage
#define BUCKET_MAX_FEEDS      32        // Range 2-64 Number of unique feeds the bucket can hold
//#define BUCKET_TIME()  GetUnixTime(); // Need to define link to function that will provide unix time to this macro
#define BUCKET_MAX_VALUE_SIZE   64      // Maximum value string length

typedef enum {
    UINT16,
    STRING
} cvalue_t;

// Used to register feeds to the bucket and for passing sensor data to the bucket
typedef struct {
    const char* key;    // MUST BE CONST, since the feeds reference key will never change.
    cvalue_t type;      // Data type     
    void* value;        // Value
    uint32_t unixTime;  // Timestamp
} cbucket_t;

bool BucketRegisterFeed(cbucket_t *feed);
int8_t BucketPut(const cbucket_t *data);
int8_t BucketGet( char *keyOut, char *dataOut, uint32_t *timestampOut);
uint8_t BucketNumbOfRegisteredFeeds(void);
void BucketZeroize(void);

//Debug functions
void DebugPrintRegistrationData(void);
void DebugPrintBucket(void);
void DebugPrintBucketTailToHead(void);


#endif /* BUCKET_H_ */

Below is the source file.

/*
 * Bucket.c
 *
 * Created: 17/12/2020 12:57:31 PM
 * Author: Vinay Divakar
 
 * Description: This module is used to accumulate data when 
    the network is down or unable to transmit data due to poor 
    signal quality. It currently supports uint16_t and string 
    data types.  The bucket is designed to maximize the amount 
    of data that can be stored in a given amount of memory for 
    typical use. The feeds must be registered before it can be 
    written to or read from the bucket. 
 
 The BucketPut API writes the feed to the bucket.
    E.g. 1: If the BucketPut sees that consecutive feeds written 
    have the same timestamp, then it writes the data as shown below. 
    This is done to save memory.
    
    (Slot) (Data) (Slot) (Data) (Slot) (Data)...(Timestamp)
                            
    E.g. 2: If the BucketPut sees that consecutive feeds written have 
    different timestamps, then it writes the data as shown below.
    
    (Slot) (Data) (Timestamp) (Slot) (Data) (Timestamp) 
    (Slot) (Data) (Timestamp)
                            
    E.g. 3: If the BucketPut sees a mixture of above, then it writes 
    the data as shown below.
    
    (Slot) (Data) (Slot) (Data) (Slot) (Data) (Timestamp) (Slot) (Data) 
    (Timestamp) (Slot) (Data) (Slot) (Data) (Timestamp)
                            
 The BucketGet API reads the feed in the following format.
 
    (Key) (Value) (Timestamp)
    
 * Notes:
    1. Module hasn't been tested for STRING data type. 
 */

/*
 *====================
 * Includes
 *====================
 */
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "atmel_start.h"
#include "Bucket.h"
//#include "INIconfig.h"

/* For debug purposes */
const char* cvaluetypes() = {"UINT16", "STRING"};

/*
*====================
* static/global vars
*====================
*/
// Stores the registered feed 
static cbucket_t *registeredFeed(BUCKET_MAX_FEEDS);
static const uint8_t unixTimeSlot = 0xFF;   //virtual time slot
// Bucket memory for edge storage and pointers to keep track or reads and writes
static uint8_t cbucketBuf(BUCKET_SIZE);
static uint8_t *cBucketBufHead = &cbucketBuf(0);
static uint8_t *cBucketBufTail = &cbucketBuf(0);

/*
*====================
* Fxns
*====================
*/
static uint8_t RegisteredFeedFreeSlot(void);

/****************************************************************
 * Function Name    : BucketZeroize
 * Description      : Zeroize the bucket
 * Returns          : None.
 * Params           :None.
 ****************************************************************/
void BucketZeroize(void){
    memset(cbucketBuf, 0, sizeof(cbucketBuf));
}

/****************************************************************
 * Function Name    : BucketGetRegisteredFeedSlot
 * Description      : Gets slot index of the registered feed
 * Returns          : slot index on OK, 0xFF on error
 * Params           @data: points to the feed struct
 ****************************************************************/
static uint8_t BucketGetRegisteredFeedSlot(const cbucket_t *data){
    uint8_t slotIdx;
    /* Check if the feed had been previously registered */
    for(slotIdx = 0 ; slotIdx < BUCKET_MAX_FEEDS ; slotIdx++) {
        //found it?
        if(data == registeredFeed(slotIdx)){
            //Get the slot index
            return(slotIdx); 
        }
    }
    return(0xFF);
}

/****************************************************************
 * Function Name    : BucketCheckDataAvailable
 * Description      : Checks for data in the bucket
 * Returns          : false on empty else true.
 * Params           None.
 ****************************************************************/
static bool BucketCheckDataAvailable(void){
    return (cBucketBufTail != cBucketBufHead);
}

/****************************************************************
 * Function Name    : BucketHeadWrapAroundToStart
 * Description      : Wraps the head to start of the bucket
 * Returns          None.
 * Params           None.
 ****************************************************************/
static void BucketHeadWrapAroundToStart(void){
    if(cBucketBufHead >= &cbucketBuf(BUCKET_SIZE)){
        cBucketBufHead = &cbucketBuf(0);    
    }
}

/****************************************************************
 * Function Name    : BucketTailWrapAroundToStart
 * Description      : Wraps the tail to start of the bucket
 * Returns          None.
 * Params           None.
 ****************************************************************/
static void BucketTailWrapAroundToStart(void){
    if(cBucketBufTail >= &cbucketBuf(BUCKET_SIZE)){
        cBucketBufTail = &cbucketBuf(0);
    }
}

/****************************************************************
 * Function Name    : BucketGetTimeStamp
 * Description      : Gets the timestamp for the specific key
 * Returns          : true on OK, false on empty
 * Params            @timestamp: Gets the timestamp while write
 ****************************************************************/
static bool BucketPutGetTimeStamp(uint32_t *timestamp){
    bool status = false;
    *timestamp = 0;
    
    //There's no data left to be read from the bucket i.e. tail = head
    if(!BucketCheckDataAvailable()){
        return(false);
    }
    
    //Attempt looking for the time slot, 
    uint8_t *cBucketBufHeadTmp = cBucketBufHead;
    //Iterate through the cells while handling wraparounds, this is to go backwards looking for the timeslot
    for(int i = 0 ; i < 5 ; i++, cBucketBufHeadTmp--){
         //if head points to start of bucket, wrap to end of the bucket
        if(cBucketBufHeadTmp <= &cbucketBuf(0)){
            cBucketBufHeadTmp = &cbucketBuf(BUCKET_SIZE);
        }
    }
    
    //Now, we should be pointing to the virtual time slot i.e. 0xff
    if(*cBucketBufHeadTmp == unixTimeSlot){
       //Inc address to skip the virtual time slot i.e. 0xFF
       cBucketBufHeadTmp++; 
        
        //load the timestamp
        for(uint8_t i = 0 ; i < sizeof(uint32_t) ; i++, cBucketBufHeadTmp++){
            //Handle if head needs to be wrapped around to read the timestamp
            if(cBucketBufHeadTmp >= &cbucketBuf(BUCKET_SIZE)){
                cBucketBufHeadTmp = &cbucketBuf(0);
            }
            *timestamp |= *(uint8_t*)cBucketBufHeadTmp << (8 * i);
        }//for
        //we found it!
        status = true;
    }//points to timeslot
    
    return(status);
}

/****************************************************************
 * Function Name    : BucketGetDataSize
 * Description      : Gets the size of the item
 * Returns          : false on error, !0 on OK
 * Params       @data :points to feed struct
 ****************************************************************/
static uint8_t BucketGetDataSize(const cbucket_t *data){
    uint8_t dataSizeOut = 0;

    switch(data->type){
        case UINT16:{
            //Total data size  = 2 bytes i.e. 16 bit unsigned
            dataSizeOut = sizeof(uint16_t); 
        }
        break;
        
        case STRING:{
            //Total data size = length of the string until null terminated. Now get the length of the string by looking upto ''
            const uint8_t *bytePtr =  (uint8_t*)data->value;
            dataSizeOut = (uint8_t)strlen((const char*)bytePtr);
            //Include the '' to be written. This will be used to indicate the end of string while reading
            dataSizeOut++;  
        }
        break;
        
        default:
        printf("(BucketGetDataSize), invalid data typern");
        break;
    }
    
    return(dataSizeOut);
}

/****************************************************************
 * Function Name    : BucketRegisterFeed
 * Description      : Registers the feed
 * Returns          : false on error, true on OK
 * Params       @feed :Feed to register
 ****************************************************************/
bool BucketRegisterFeed(cbucket_t *feed) {
    uint8_t slot = RegisteredFeedFreeSlot();
    if (slot >= BUCKET_MAX_FEEDS){
        return(false);
    } else{
        registeredFeed(slot) = feed;    
    }
    return (true);
}

/****************************************************************
 * Function Name    : BucketGetTimestampForFeed
 * Description      : Gets the timestamp for the feed
 * Returns          : false on error, true on OK.
 * Params           @timestamp: feeds timestamp while read
 ****************************************************************/
static bool BucketGetTimestampForFeed(uint32_t *timestamp){
    int8_t status = false;
    *timestamp = 0;
    
    BucketTailWrapAroundToStart();
    //Check if tail is pointing to the virtual time slot
    if(*cBucketBufTail == unixTimeSlot){//If so, read the timestamp
        printf("(BucketGetTimestampForFeed), tail pointing to time slot, read it.rn");
        *cBucketBufTail++ = 0;  //Skip the virtual timeslot and point to the timestamp
        for(uint8_t i = 0 ; i < sizeof(uint32_t) ; i++){
            BucketTailWrapAroundToStart();
            *timestamp |= *(uint8_t*)cBucketBufTail << (8 * i);
            *cBucketBufTail++ = 0;
        }//for
        status = true;
    }else{//timeslot not found?
        //means the next byte is the slot index for the next feed which is not what we are looking for.
        //Lets look beyond, it must be there! - if not, then there's something seriously wrong with the code
        uint8_t *cBucketBufTailTmp = cBucketBufTail;
        //Iterate and look for the time slot
        while(cBucketBufTailTmp++ <= &cbucketBuf(BUCKET_SIZE)){
                if(cBucketBufTailTmp >= &cbucketBuf(BUCKET_SIZE)){
                    cBucketBufTailTmp = &cbucketBuf(0);
                }
            //Check if we are pointing to the virtual time slot
            if(*cBucketBufTailTmp == unixTimeSlot){
                printf("(BucketGetTimestampForFeed), yes!, time slot has been found.rn");             
                cBucketBufTailTmp++;//Skip the virtual timeslot and point to the start of the timestamp
                for(uint8_t  i = 0 ; i < sizeof(uint32_t) ; i++, cBucketBufTailTmp++){
                    if(cBucketBufTailTmp >= &cbucketBuf(BUCKET_SIZE)){
                        cBucketBufTailTmp = &cbucketBuf(0);
                    }
                    *timestamp |= *(uint8_t*)cBucketBufTailTmp << (8 * i);
                }//read the timestamp
                status = true;
                break;
            }//timeslot
        }//while
    }//else
    return(status);
}

/****************************************************************
 * Function Name    : BucketGetReadData
 * Description      : Reads the key and value for that feed/slot.
 * Returns          : false error, true on success.
 * Params           @key: key to be populated(static).
                    @value: value read from the bucket.
 ****************************************************************/
static bool BucketGetReadData(char *key, char *value){
    uint8_t slotIdx;
    bool status = true;
    
    //Check if the tail is pointing to the end of the bucket or beyond, wrap around to start of bucket to continue reading
    BucketTailWrapAroundToStart();
        
    //Read the slot index for the feed
    slotIdx = *(uint8_t*)cBucketBufTail;    //this is an int8_t type, if greater, will lead to undefined behavior.
    *cBucketBufTail++ = 0;
    if(slotIdx > BUCKET_MAX_FEEDS){ 
        printf("(BucketGetReadData), Error, Slot(%u) index is out of boundsrn", slotIdx); 
        return(false); 
    }else{
        printf("(BucketGetReadData), Slot(%d) = %prn", slotIdx, (void *)registeredFeed(slotIdx)->key);
    }
    //Copy the key for the corresponding slot
    strncpy(key, registeredFeed(slotIdx)->key, strlen(registeredFeed(slotIdx)->key));
    
    //Read data based on type
    switch(registeredFeed(slotIdx)->type){
        case UINT16:{
            uint16_t dataU16 = 0;
            for(uint8_t i = 0 ; i < sizeof(uint16_t) ; i++){//Read 2 bytes
                BucketTailWrapAroundToStart();
                dataU16 |= *cBucketBufTail << (8 * i);
                *cBucketBufTail++ = 0;
            }//for
            printf("(BucketGetReadData) dataU16 = %hu (0x%X)rn", dataU16, dataU16);
            sprintf(value, "%hu", dataU16); //convert the u16 into string
        }
        break;
        
        case STRING:{
            uint8_t i = 0; printf("(BucketGetReadData) dataStr = ");
            while(*cBucketBufTail != ''){
                BucketTailWrapAroundToStart();
                printf("0x%x ", *cBucketBufTail);
                value(i++) = *cBucketBufTail;
                *cBucketBufTail++ = 0;
            }//copy data until end of string is reached
            //copy the null terminated character and point to start of the next address
            value(i) = *cBucketBufTail;
            *cBucketBufTail++ = 0;
            printf("rn");
        }
        break;
        
        default:
        printf("(BucketGetReadData), Error, invalid read type Slot(%d)rn", slotIdx);
        status = false;
        break;
    }
    
    return(status);
}

/****************************************************************
 * Function Name    : RegisteredFeedFreeSlot
 * Description      : Gets first free slot(index) found, returns
 * Returns          : slot on success else 0xFF
 * Params       None.
 ****************************************************************/
static uint8_t RegisteredFeedFreeSlot(void) {
    uint8_t slot;
    //Check for slots sequentially, return index of first empty one (null pointer)
    for(slot = 0; slot < BUCKET_MAX_FEEDS; slot++) {
        if(registeredFeed(slot) == 0) 
            return (slot);
    }
    //All slots full
    return (0xFF); 
}

/****************************************************************
 * Function Name    : CircularBufferWrite
 * Description      : Writes data to the bucket
 * Returns          None.
 * Params           @itemSize: Size of the data
                    @data: ptr to data to be written
 ****************************************************************/
static void CircularBufferWrite(uint8_t itemSize, uint8_t *data){
    for(uint8_t i = 0 ; i < itemSize ; i++, cBucketBufHead++){
        BucketHeadWrapAroundToStart();
        *cBucketBufHead = data(i);
    }
}

/****************************************************************
 * Function Name    : BucketPrepareFrame
 * Description      : Prepares frame to be written to the bucket
 * Returns          None.
 * Params           @dataSizeIn: Size of actual feed data
                    @frameOut: ptr to frame buffer
                    @slotIn: slot index for the feed
                    @dataIn: ptr to the feed struct.
 ****************************************************************/
static void BucketPrepareFrame(uint8_t dataSizeIn, uint8_t *frameOut, uint8_t slotIn, const cbucket_t *dataIn){
    uint8_t i = 0;
    uint8_t *bytePtr =  (uint8_t*)dataIn->value;
    for(i = 0 ; i <= dataSizeIn ; i++){
        if(i == 0){
            frameOut(i) = slotIn;//copy slot index
        }else{
            frameOut(i) = *bytePtr++; //copy data
        }
    }

    frameOut(i++) = unixTimeSlot; //copy timeslot index
    for(uint8_t j = 0 ; j < sizeof(dataIn->unixTime); j++){
        frameOut(i++) = (dataIn->unixTime  >> 8*j) & 0xFF; //copy the timestamp
    }
}

/****************************************************************
 * Function Name    : BucketPut
 * Description      : writes to the bucket
 * Returns          : true on success else negative..
 * Params       @data :points to struct to be written
 ****************************************************************/
int8_t BucketPut(const cbucket_t *data) {
    uint8_t slot = 0;
    uint8_t dataSize = 0;
    uint8_t totalSpaceRequired = 0;
    uint16_t remaining = 0;
    uint32_t lastStoredTime = 0;
    uint8_t frame(64);
    
    //Find the slot for this feed
    slot = BucketGetRegisteredFeedSlot(data);
    if(slot > BUCKET_MAX_FEEDS){ 
        printf("(BucketPut), Error, feed not registeredrn"); 
        return(-1); 
    }
        
    //Get th size of the item and handle storing as appropriate 
    dataSize =  BucketGetDataSize(data);
    if(dataSize == false){  
        printf("(BucketPut), Error, invalid data typern");  
        return(-2); 
    }
    
    //Get the amount space left in the bucket 
    remaining = (cBucketBufTail + BUCKET_SIZE - cBucketBufHead-1) % BUCKET_SIZE;
    printf("(BucketPut), bucket size = %d   remaining space = %hu   dataSize = %urn", (int)BUCKET_SIZE, remaining, dataSize);
    
    //Get the timestamp from the unix time slot 
    bool found = BucketPutGetTimeStamp(&lastStoredTime);
    if(found){//last stored timestamp found
        printf("(BucketPut) Last stored timestamp(%lu) foundrn", lastStoredTime);
    }
    
    //Check timestamps
    if(lastStoredTime == data->unixTime){
        //If timestamp matches the current feed, write only data and slot idx
        printf("(BucketPut), (%lu) timestamps matched!rn",data->unixTime);
        totalSpaceRequired = (uint8_t)(dataSize + sizeof(slot));
    }else{
        //If timestamps different or unavailable, account for a write including the new timestamp
        printf("(BucketPut) Last stored timestamp(%lu) is different from Current feed timestamp(%lu)rn", lastStoredTime, data->unixTime);
        totalSpaceRequired = (uint8_t)(dataSize + sizeof(slot) + sizeof(data->unixTime) + sizeof(unixTimeSlot));
    }
    
    //Proceed further only if enough space is available in the bucket
    if(totalSpaceRequired > remaining) {
        printf("(BucketPut), Error, no space available, space = %hu,    required space = %hurn", remaining, totalSpaceRequired);
        return(-3);
    }else{
            printf("(BucketPut), available space = %hu  required space = %hurn", remaining, totalSpaceRequired);
    }
    
    //If timestamp had matched, overwrite it with current feed data and append with timestamp.
    if(lastStoredTime == data->unixTime){
        uint8_t shiftOffset = sizeof(slot) + sizeof(data->unixTime);
        //move the head backwards by size of time slot index + size of timestamp.
        for(int i = 0 ; i < shiftOffset ; i++, cBucketBufHead--){
            if(cBucketBufHead <= &cbucketBuf(0)){
                cBucketBufHead = &cbucketBuf(BUCKET_SIZE);
            }
        }//for
    }//timestamp matched!
    
    //Get the size of the item based on the data type
    uint8_t totalItemSize = (uint8_t)(dataSize + sizeof(slot) + sizeof(data->unixTime) + sizeof(unixTimeSlot));
    
    //Prepare data to be written to the bucket
    if(totalItemSize > sizeof(frame)){
        printf("(BucketPut), Error, item size is very largern");
        return(-4);
    }
    
    //If we have reached here, means all checks have passed and its safe to write the item to the bucket 
    memset(frame, 0, sizeof(frame));
    BucketPrepareFrame(dataSize, frame, slot, data);
    CircularBufferWrite(totalItemSize, frame);

    return(true);
}

/****************************************************************
 * Function Name    : BucketGet
 * Description      :Gets the data
 * Returns          : true on success else negative..
 * Params       @keyOut :contains the key
                @dataOut:contains the value
                @timestampOut: contains the timestamp
 ****************************************************************/
int8_t BucketGet( char *keyOut, char *dataOut, uint32_t *timestampOut) {
    //Check if theres anything in the bucket
    printf("<==============================================================================>rn");
    if(!BucketCheckDataAvailable()){
        printf("(BucketGet), AlLERT, Bucket is empty, no more data left to read.rn");
        return(-1);
    }
    
    //Read the key-value for the corresponding feed/slot
    if(!BucketGetReadData(keyOut, dataOut)){ 
        printf("(BucketGet), Error, bucket read failedrn"); 
        return(-2); 
    }
    //Read the timestamp corresponding to this feed
    if(!BucketGetTimestampForFeed(timestampOut)){
        printf("(BucketGet), Error, feed timestamp read failedrn"); 
        return(-3); 
    }
    //All good, dump the key-value and associated timestamp
    printf("(Bucket Get) timestamp  = %lu rn",*timestampOut);
    printf("(Bucket Get) key        = %srn", keyOut);
    printf("(Bucket Get) value      = %srn", dataOut);
    printf("<==============================================================================>rn");
        
    return(true);
}

/****************************************************************
 * Function Name    : BucketNumbOfRegisteredFeeds
 * Description      : Gets the num of registered feeds
 * Returns          : No. of registered feeds
 * Params       None.
 ****************************************************************/
uint8_t BucketNumbOfRegisteredFeeds(void) {
    uint8_t slot;
    // Check for slots sequentially, return index of first empty one (null pointer)
    for(slot = 0; slot < BUCKET_MAX_FEEDS; slot++) {
        if(registeredFeed(slot) == 0)
        break;
    }
    return (slot);
}

/*
*====================
* Debug Utils
*====================
*/
/****************************************************************
 * Function Name    : PrintFeedValue
 * Description      :Prints feed data value via void pointer
 and corrects for type FLOAT AND DOUBLE DONT PRINT ON WASPMOTE
 BUT NO REASON TO BELIEVE THEY ARE WRONG
 * Returns          : None.
 * Params       @feed: Points to the feed to be printed
 ****************************************************************/
void PrintFeedValue(cbucket_t *feed) {
    
    switch(feed->type){
        case UINT16:
            printf("%d",*(uint16_t*)feed->value);
        break;
        
        case STRING:
             printf("%s",(char*)feed->value);
        break;
        
        default:
            printf("%s","UNSUPPORTED TYPE");
        break;
    }
}

/****************************************************************
 * Function Name    : _DebugPrintRegistrationData
 * Description      :Prints all registered feeds and their details
 * Returns          : None.
 * Params       None.
 ****************************************************************/
void DebugPrintRegistrationData(void) {
    uint8_t slot;

    printf("********************** Current Bucket Registration Data **************************rn");
    printf("slottaddresstkeyttypetvaluetunixtimern");
    for(slot = 0; slot<BUCKET_MAX_FEEDS; slot++) {
        printf("%dt", slot);                                        // Print index
        if (registeredFeed(slot) != NULL) {
            printf("%pt",(void *)registeredFeed(slot)->key);                 // Print structure address
            printf("%st",registeredFeed(slot)->key);                  // Print key
            printf("%st",cvaluetypes(registeredFeed(slot)->type));    // Print type
            PrintFeedValue(registeredFeed(slot));                      // Print value
            printf("t%lurn",registeredFeed(slot)->unixTime);        // Print time
        } else printf("--t--tEMPTYt--t--rn");
    }
}

/****************************************************************
 * Function Name    : _DebugPrintBucket
 * Description      :Prints all bucket memory, even if empty
 * Returns          : None.
 * Params       None.
 ****************************************************************/
void DebugPrintBucket(void) {
    uint16_t readIndex = 0;
    printf("rn********************* BUCKET START ********************rn");
    while(readIndex < BUCKET_SIZE) {
        printf("0x%04X ", readIndex);
        for (uint8_t column = 0; column < 16; column++) {
            if(readIndex < BUCKET_SIZE) printf("%02X ",cbucketBuf(readIndex));
            readIndex++;
            //delayMicroseconds(78);  // Wait for a byte to send at 115200 baud
            //delay(0.1);
        }
        printf("rn");
    }
    printf("********************** BUCKET END *********************rn");
}

/****************************************************************
 * Function Name    : _DebugPrintBucket
 * Description      : Prints bucket memory that has data
 * Returns          : None.
 * Params       None.
 ****************************************************************/
void DebugPrintBucketTailToHead(void) {
    uint8_t *cBucketBufHeadTemp = cBucketBufHead;
    uint8_t *cBucketBufTailTemp = cBucketBufTail;
    uint16_t index;
    printf("n*************** BUCKET START FROM TAIL ****************n");
    // Label and indent first line
    if ((cBucketBufTailTemp - &cbucketBuf(0)) % 16 != 0) {
        printf("          ");
        for (index = (uint16_t)(cBucketBufTailTemp - &cbucketBuf(0)) % 16; index > 0; index--) {
            printf("   ");
        }
    }
    // Print rest of data
    while(cBucketBufTailTemp != cBucketBufHeadTemp) {                                                                  // Increment read address
        if(cBucketBufTailTemp >= &cbucketBuf(BUCKET_SIZE)) cBucketBufTailTemp = &cbucketBuf(0); // Handle wraparound
        index = (uint16_t)(cBucketBufTailTemp - &cbucketBuf(0));                                            // Get current index in buffer
        if (index % 16 == 0) printf("n0x%04X ", cBucketBufTailTemp - &cbucketBuf(0));          // New line every 0x00n0
        printf("%02X ", *cBucketBufTailTemp);
        cBucketBufTailTemp++;                                                   // Print data in buffer
    }
    printf("n***************** BUCKET END AT HEAD ******************n");
}

Below is the test code

char sensorValStr1()    = "aaaaaaa";
char sensorKey1()       ="sensorRef1";
cbucket_t sensor1       = {sensorKey1, STRING, sensorValStr1,               1613343690};

uint16_t sensorValU16_2 = 0xAAAA;
char sensorKey2()       ="sensorRef2";
cbucket_t sensor2       = {sensorKey2, UINT16, (uint8_t*)&sensorValU16_2,   1613343689};

uint16_t sensorValU16_3 = 0xBBBB;
char sensorKey3()       ="sensorRef3";
cbucket_t sensor3       ={sensorKey3, UINT16, (uint8_t*)&sensorValU16_3,    1613343689};

uint16_t sensorValU16_4 = 0xCCCC;
char sensorKey4()       ="sensorRef4";
cbucket_t sensor4       ={sensorKey4, UINT16, (uint8_t*)&sensorValU16_4,    1613343691};
    
int main(void) {
    char keyOutT(32) = {0};
    char valOutT(32) = {0};
    int8_t status = 0;
    uint32_t timeStmp = 0;
    
    //Initialize drivers
    //atmel_start_init();                   

    BucketRegisterFeed(&sensor1);
    BucketRegisterFeed(&sensor2);
    BucketRegisterFeed(&sensor3);
    BucketRegisterFeed(&sensor4);
    DebugPrintRegistrationData();
    
    printf("=========================================================================================================rn");
    printf("(BucketPut), Test case-1: Checking the bucket does not overflow when filled with data same timestamps...rn");
    printf("=========================================================================================================rn");
    status = false;
    for(int i = 0 ; i < 10; i++){
        status = BucketPut(&sensor2);
        if(status == -3)
            break;
    }
    
    if(status == -3){
        printf("Test case-1: PASSEDrn");
    }else{
        printf("Test case-1: FAILEDrn");
    }
    DebugPrintBucket();
    
    //Empty the bucket
    while(true){
        int8_t status = BucketGet(keyOutT, valOutT, &timeStmp);
        if(status < 0){
            break;
        }else{
            DebugPrintBucket();
        }
    }

    printf("=========================================================================================================rn");
    printf("(BucketPut), Test case-2: Checking the bucket does not overflow when filled with data different timestamps...rn");
    printf("=========================================================================================================rn");
    status = false;
    for(int i = 0 ; i < 5 ; i++){
        status = BucketPut(&sensor2);
        if(status == -3){//bucket is full
            //do nothing
        }else{
            sensor2.unixTime += 1;
        }
    }
        
    if(status == -3){
        printf("Test case-2: PASSEDrn");
    }else{
        printf("Test case-2: FAILEDrn");
    }
    DebugPrintBucket();
    
    //Empty the bucket
    while(true){
        int8_t status = BucketGet(keyOutT, valOutT, &timeStmp);
        if(status < 0){
            break;
        }else{
            DebugPrintBucket();
        }
    }
    
    printf("=========================================================================================================rn");
    printf("(BucketPut), Test case-3: Checking the bucket write mixture of data same and different timestamps...rn");
    printf("=========================================================================================================rn");
    
    status = false;
    for(int i = 0 ; i < 5 ; i++){
        status = BucketPut(&sensor3);
        if(status == -3){//bucket is full
            //do nothing
        }else{
            if(i == 2){
                
            }else if(i == 3){
                
            }else{
                sensor2.unixTime += 1;  
            }
        }//else
    }
    DebugPrintBucket();
    
    //Empty the bucket
    while(true){
        int8_t status = BucketGet(keyOutT, valOutT, &timeStmp);
        if(status < 0){
            break;
        }else{
            DebugPrintBucket();
        }
    }
    
    printf("=========================================================================================================rn");
    printf("(BucketPut), Test case-3: Checking the bucket write with timestamp wrapped around end-->startrn");
    printf("=========================================================================================================rn");
    
    status = false;
    for(int i = 0 ; i < 2; i++){
        if(i == 0){
            BucketPut(&sensor1);
        }
        status = BucketPut(&sensor2);
        if(status == -3)
        break;
    }
    DebugPrintBucket();
    
    //Empty the bucket
    while(true){
        int8_t status = BucketGet(keyOutT, valOutT, &timeStmp);
        if(status < 0){
            break;
        }else{
            DebugPrintBucket();
        }
    }
    
    printf("=========================================================================================================rn");
    printf("(BucketPut), Test case-4: Checking the bucket write with mix of string and uint16_trn");
    printf("=========================================================================================================rn");
    status = false;
    for(int i = 0 ; i < 4; i++){
        if(i == 0){
            BucketPut(&sensor1);
        }
        status = BucketPut(&sensor3);
        if(status == -3)
        break;
    }
    DebugPrintBucket();
        
    //Empty the bucket
    while(true){
        int8_t status = BucketGet(keyOutT, valOutT, &timeStmp);
        if(status < 0){
            break;
        }else{
            DebugPrintBucket();
        }
    }
    
    while (true) {
        //empty loop
    }
}

firebase – ¿Instale la misma dependencia de forma global y en un proyecto? ¿Ahora quiero ejecutar la local, como especifico que quiero la local y no la global?

Instale firebase-tools para usar firebase.

Tenia instalada esa herramienta de forma global.

Pero ahora la instale como dependencia de desarrollo.

quiero ejecutar el comando firebase login para empezar a usar la herramienta, pero quiero usar la versión que instale de forma local, ¿como puedo indicar que quiero esa versión especifica?.

las dos cosas las he instalado con node package manager (npm)

Tits reductive groups over local fields, 1.15/3.11. Problem with affine root subgroups of $SU_3$ ramified, residue characteristic p=2

Let $L/K$ be ramified quadratic extension of local fields, and let characteristic of the residue field of $K$ be $2$. Let $mathbb{G}=SU_3$, $G=mathbb{G}(K)$. Let $text{val}$ be a valuation on $K$ so that $text{val}(K^times) = mathbb{Z}$ (and $text{val}(L^times) = frac{1}{2}mathbb{Z}$).

Following Tits 1.15 and 3.11, I have been trying to work out the parahoric subgroups of $G$ attached to the special vertices $nu_0$ and $nu_1$ in the building of $G$.

Firstly, I’ll start with a description of the root subgroups of $G$. I’m using a slightly different notation from Tits’. Let $$u_+(c,d) = begin{pmatrix} 1 & -bar{c} & d \ 0 & 1 & c \ 0 & 0 & 1 end{pmatrix},$$
with $bar{c}c+d+bar{d}=0$.
Similarly, $$u_-(c,d) = begin{pmatrix} 1 & 0 & 0 \ c & 1 & 0 \ d & -bar{c} & 1 end{pmatrix},$$
with $bar{c}c+d+bar{d}=0$.

We have the root subgroups $U_{pm a}(K) = { u_pm(c,d) text{ : } c,d in L }$ and $U_{pm 2a} = { u_pm(0,d) text{ : } d in L}$.

Tits later defines $delta = sup{text{val}(d) text{ : } d in L, , bar{d}+d+1=0}$. $delta=0$ in the unramified case and in the ramified, residue characteristic $pneq 2$ case. However, when $L/K$ is ramified with residue characteristic $2$, $delta$ is strictly negative.

From here, Tits finds the set of affine roots of $G$ as $$Big{pm a + frac{1}{2}mathbb{Z} +frac{delta}{2}Big} cup Big{pm 2a +mathbb{Z}+ frac{1}{2} + delta Big}.$$

Affine root subgroups are given by $$U_{pm a + gamma/2} = { u_pm(c,d) text{ : } text{val}(d) geq gamma},$$
$$U_{pm 2a+ gamma} = { u_pm(0,d) text{ : } text{val}(d) geq gamma}.$$

The special points $nu_0$ and $nu_1$ i the standard apartment are defined by $$a(nu_1)=frac{delta}{2}, , a(nu_0) = frac{delta}{2} + frac{1}{4}.$$

From here, one can find that $$G_{nu_1} = langle T_0, U_{a-frac{delta}{2}}, U_{-a+frac{delta}{2}}, U_{2a+frac{1}{2}-delta}, U_{-2a+frac{1}{2}+delta} rangle,$$
$$G_{nu_0} = langle T_0, U_{a-frac{delta}{2}}, U_{-a+frac{1}{2}+frac{delta}{2}}, U_{2a-frac{1}{2}-delta}, U_{-2a+frac{1}{2}+delta} rangle.$$

In 3.11, Tits takes a $lambda in L$ with $text{val}(lambda) = delta$, satisfying $lambda+bar{lambda}+1=0$ in a way such that $lambda varpi_L + overline{(lambda varpi_L)}=0$ for some uniformizer $varpi_L$ of the ring of integers $mathcal{O}_L$ of $L$.

In 3.11, Tits defines the lattices $$Lambda_{nu_1} = mathcal{O}_L oplus mathcal{O}_L oplus lambdamathcal{O}_L,$$
$$Lambda_{nu_0} = varpi_L^{-1}mathcal{O}_L oplus mathcal{O}_L oplus lambdamathcal{O}_L.$$ Let $P_{nu_1}$ and $P_{nu_0}$ be their respective stabilizers.
Tits then states that $G_{nu_i} = P_{nu_i} cap G_{nu_i}$ for $i=0,1$.

Here’s where my problem comes in.

Consider $G_{nu_1} = langle T_0, U_{a-frac{delta}{2}}, U_{-a+frac{delta}{2}}, U_{2a+frac{1}{2}-delta}, U_{-2a+frac{1}{2}+delta} rangle.$ The stabilizer of the lattice $Lambda_{nu_1}$ in $GL_3(L)$ has the form
$$begin{pmatrix} mathcal{O}_L & mathcal{O}_L & mathfrak{p}_L^{-2delta} \ mathcal{O}_L & mathcal{O}_L & mathfrak{p}_L^{-2delta} \ mathfrak{p}_L^{2delta} & mathfrak{p}_L^{2delta} & mathcal{O}_L end{pmatrix}.$$
Since $text{val}(delta) < 0$, intersecting this stabilizer with $G$ would give us a matrix roughly looking like
$$begin{pmatrix} mathcal{O}_L & mathfrak{p}_L^{-2delta} & mathfrak{p}_L^{-2delta} \ mathcal{O}_L & mathcal{O}_L & mathfrak{p}_L^{-2delta} \ mathfrak{p}_L^{2delta} & mathcal{O}_L & mathcal{O}_L end{pmatrix},$$

Presumeably, this would tell us that $$U_{a-frac{delta}{2}} = { u_+(c,d) text{ : } c,d in L, , text{val}(d) geq -delta textbf{ and } text{val}(c) geq -delta },$$
$$U_{-a+frac{delta}{2}} = {u_{-}(c,d) text{ : } c,d in L, , text{val}(d) geq delta textbf{ and } text{val}(c) geq 0 }.$$
Normally, one would expect that if $text{val}(d) = gamma$, then $text{val}(d) = frac{gamma}{2}$ or $frac{gamma}{2}+frac{1}{4}$, as whether $gamma in mathbb{Z}$ or just $frac{1}{2}mathbb{Z}$.

I cannot work out algebraically why we have these improved bounds on the valuation of $c$ for these affine root subgroups. I assume it involves some manipulation with $lambda$, but I am not making any progress.

Thank you

authentication – Always re-authenticating when clicking on link in local HTML file

I log in to a web site, such as https://myaccount.example.com.

I paste a URL into the address bar from that domain, such as https://myaccount.example.com/desserts/pie. The page loads because I am already authenticated.

I have a local HTML file with a link to the same page. This file is not running on a local web server.

<a href="https://myaccount.example.com/desserts/pie" target="pu">Pies</a>
  • The server asks me to authenticate!
  • When I do authenticate, and click on the link again, the server again asks me to authenticate.

Why does this happen?

I will add ca business in top canada directory and local citations for $12

I will add ca business in top canada directory and local citations

About This Gig

Hi,

Welcome to Services97

I will list your business in 25, 50 and 100 TOP Rated Canadian directories manually,

I have a lot of experience in Local SEO, Directory Submission and built local Citation,

  • This gig is only for CANADA directories if you want to send your business other than Canada, just visit my other cool gigs at www.fiverr.com/services97
  • All Directory submission / Citations from CA / Local IP address
  • 100% Manual Work NAP Constant for ALL Citations.
  • 100% Customer Satisfaction
  • 100% Lifetime support
  • We only target the related listings which are relevant to your business
  • Full Report With Login Details.

Looking for Citation CleanUp? just click on below URL

www.fiverr.com/s2/25e797ca25

Benefits:

1- You will get quality back-links to increase the position of your business in local search ranking.

2- It will increase the authority of your website.

3- Dramatically improve your local search engine rankings.

Looking to add your business in USA or UK directories?

for USA– www.fiverr.com/s2/28d09ec09f

for UK– www.fiverr.com/s2/52cf9ebd83

IF you need Quality work just Order now!

.

database design – How to model local exceptions to distributed tables

I am looking for possible ways to model a distributed table(s) and provide local exceptions to that table. Consider a situation where head office publishes a list of products/prices that is distributed to branches and they load this price list into their local database. Now sometimes these branches want to change the head office price to a local price. Clearly we can simply update the price in the local database, but then it gets lost when the next head office update is applied. We also only want to block that single column(s), not changes to other fields in the row.

EG. Head office send

| Name | Price |
|------|-------|
| ABC  | $5    |
| DEF  | $8    |

In one database (out of say 100) we want ABC to have a price of $3. And this $3 should continue to apply even as future updates from head office are received. Head office are not aware of this local exeception.

In the past we’ve done this in two ways. The first was to maintain a second LocalProducts table with the changes to be applied – then when the head office version was applied, any local changes would then be read from LocalProducts and replace the distributed value.
This works OK, but suffers as the table sizes go up.

The second method we tried was to duplicate the column and use coalesce
eg rather than select price where name='abc' we would use select coalesce(localprice,price) where name='abc' This works ok, but had the overhead that we had to change every SQL and remember to do it on future development too.

Are there any other better methods? I am looking for a database agnostic solution, the target databases are ODBC (90% sql/server), SQL-Lite or MS-Access. Access can be ignored if it helps, it is being actively phased out. Engine specific solutions are ok, we can detect the engine and use a different technique, but would prefer not to have a different technique for each engine.

Other notes

  • The data is distributed by the application, not built in replication. This means we can have code/logic during the loading phase
  • Multiple tables are require this feature, not just one as the example above
  • Some of the tables have a reasonable number of columns that could be involved, but typically not.
  • Most of the tables aren’t large, perhaps 50M rows in the biggest, and only 7 rows in the smallest case.

(please feel free to retag this question – not exactly sure which tags are relevant. And yes I have spent many hours over the years investigating this)

magento2.4.0 – Magento 2.4 installation on local returning elasticsearch error

I have installed elasticsearch on local (xampp) and on http://localhost:9200/ is showing it is running.
But when I trying to install magento 2.4 getting elasticsearch error.

Magento installation command –

php bin/magento setup:install --base-url="http://127.0.0.1/magento2" --db-host="localhost" --db-name="magento2" --db-user="root" --db-password="" --admin-firstname="Test" --admin-lastname="Test" --admin-email="test@gamil.com" --admin-user="admin" --admin-password="admin123" --language="en_US" --currency="INR" --timezone="Asia/Kolkata" --use-rewrites="1" --backend-frontname="admin" --elasticsearch-host=elasticsearch --elasticsearch-port=9200

And getting below error –

Installing search configuration...

In SearchConfig.php line 81:

  Could not validate a connection to Elasticsearch. No alive nodes found in your cluster

What should I try to install magento 2.4?

linux networking – Routing traffic from a bridge interface (with IP assigned) to another network on a different local interface

I’m on Ubuntu 20.04 and am running virtual machines (KVM) locally that are attached to a bridge interface on the host. The bridge (and all VMs attached to it) are getting their IPs via DHCP from a DSL/router on the same network.

The bridged interface on the VM host looks like this:

br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.188.22  netmask 255.255.255.0  broadcast 192.168.188.255
        inet6 fe80::2172:1869:b4cb:ec84  prefixlen 64  scopeid 0x20<link>
        inet6 2a01:c22:8c21:4200:6dd0:e662:4f46:c591  prefixlen 64  scopeid 0x0<global>
        inet6 2a01:c22:8c21:4200:8d92:1ea5:3c93:3668  prefixlen 64  scopeid 0x0<global>
        ether 00:d8:61:9d:ad:c5  txqueuelen 1000  (Ethernet)
        RX packets 1512101  bytes 2026998740 (2.0 GB)
        RX errors 0  dropped 12289  overruns 0  frame 0
        TX packets 849612  bytes 1582945488 (1.5 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

I’ve enabled IP forwarding on the host and configured the VMs to use the host as the gateway.

This is how the routes look like inside a VM:

# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.188.22  0.0.0.0         UG    0      0        0 eth0
192.168.188.0   0.0.0.0         255.255.255.0   U     100    0        0 eth0

Routes on the VM host:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.188.1   0.0.0.0         UG    425    0        0 br0
10.8.0.1        10.8.0.17       255.255.255.255 UGH   50     0        0 tun0
10.8.0.17       0.0.0.0         255.255.255.255 UH    50     0        0 tun0
172.28.52.0     10.8.0.17       255.255.255.0   UG    50     0        0 tun0
192.168.4.0     10.8.0.17       255.255.255.0   UG    50     0        0 tun0
192.168.5.0     10.8.0.17       255.255.255.0   UG    50     0        0 tun0
192.168.10.0    10.8.0.17       255.255.255.0   UG    50     0        0 tun0
192.168.50.0    10.8.0.17       255.255.255.0   UG    50     0        0 tun0
192.168.100.0   10.8.0.17       255.255.255.0   UG    50     0        0 tun0
192.168.188.0   0.0.0.0         255.255.255.0   U     425    0        0 br0
192.168.188.1   0.0.0.0         255.255.255.255 UH    425    0        0 br0
213.238.34.194  192.168.188.1   255.255.255.255 UGH   425    0        0 br0
213.238.34.212  10.8.0.17       255.255.255.255 UGH   50     0        0 tun0

Accessing IPs on the 192.168.188.0/24 network and public internet from inside the virtual machines works fine but I can’t seem to figure out how to route traffic from inside the VMs to any of the IPs/networks that are reachable through the “tun0” interface on the VM host itself.

/proc/sys/net/ipv4/ip_forward is set to “1” , I’ve manually (using iptables -F) flushed all firewall rules from all tables/chains to avoid any interference … what more do I need to be able to do (for example) “ping 192.168.50.2” from inside one of the virtual machines ?

This is what I captured by running “tcpdump -i br0 host ” on the VM host while trying to access 192.168.50.212 (one of the machines on the “tun0” network) from inside one of the VMs:

enter image description here

How can I get the VMs attached to the local “br0” interface to also have connectivity with the networks accessible only through the local “tun0” device ?