Jump to content
PLC Forum

Cesare Nicola

Le variabili in formato STRING vanno inizializzate?

Recommended Posts

Cesare Nicola

Mi è capitata una cosa strana, che non sono ancora ben riuscito a capire, quindi perdonatemi se la descrizione non dovesse essere chiara. E' possibile che una variabile in formato STRING contenuta in una DB non possa essere scritta dal PLC perché non ancora inizializzata? Per riuscire a scrivere da PLC in tante variabili stringa ho dovuto, prima, da tabella delle variabili o da HMI, scrivere dei caratteri qualunque nella stringa e da quel momento tutto ha funzionato. Nel valore di avvio della variabile ho '' . Forse '' rappresenta "nulla" e quindi al primo caricamento della DB la variabile stringa non contiene davvero nulla, né caratteri né lunghezza (che è nei i primi due byte)?  Quindi, se è come dico, una variabile stringa sarebbe meglio non avesse '' come valore di avvio (a meno che, con certezza, non mi capiti di doverla scrivere almeno una volta, magari da HMI)? Questa cosa della inizializzazione mi viene in mente perché ho dei vaghi ricordi di averla letta da qualche parte. Spero di aver reso l'idea.

Link to post
Share on other sites

walterword

se la variabile stringa la dichiari come String viene creato un puntatore a caratteri di dimensione 254 + 2 che sono i caratteri finali.

Se invece la dichiari come  myvar -> String[30] allora viene allocata una memoria di 30 + 2 bytes .

comunque ho appena provato con V15.1 , simulatore e pannello e non mi risulta quello che dici.

Col vecchio Step 7 invece ho avuto anche io lo stesso "problema" 

Sta di fatto che una stringa è un oggetto puntatore lo vedi nella tabella delle forzature P#.....

Se devi manipolare le stringhe a runtime ossia riempirle o ricavarci informazioni ti conviene appoggiarti a variabili array di char e lavorare con SCL. Puoi sempre puntare ad ogni singolo carattere della stringa con mystring[n]:= 'F'; 

Dimenticavo , DB non ottimizzato

Edited by walterword
Link to post
Share on other sites
Cesare Nicola
1 ora fa, walterword ha scritto:

se la variabile stringa la dichiari come String viene creato un puntatore a caratteri di dimensione 254 + 2 che sono i caratteri finali.

Se invece la dichiari come  myvar -> String[30] allora viene allocata una memoria di 30 + 2 bytes 

Sì, questo lo sapevo. Le stringhe in questione sono dichiarate string[10].

 

1 ora fa, walterword ha scritto:

Se devi manipolare le stringhe a runtime ossia riempirle o ricavarci informazioni ti conviene appoggiarti a variabili array di char e lavorare con SCL. Puoi sempre puntare ad ogni singolo carattere della stringa con mystring[n]:= 'F'; 

Questo è il codice in questione:


IF "DB_Tracking".Model_change_trig_R[1] THEN   // trigger da HMI, impostato a "fine immissione" della variabile che è più sotto,  "DB_Tracking".Oven_lane_1R.Model.Number;
    "DB_Tracking".Model_change_trig_R[1] := false;  // reset trigger
    #Nbr := "DB_Tracking".Oven_lane_1R.Model.Number; // appoggio su una TEMP col nome corto
    IF "DB_Tracking".Oven_lane_1R.Model.Number = 0 THEN  // se la variabile che ho appena modificato da HMI vale zero... 
        "DB_Tracking".Oven_lane_1R.Model.Name := '';  // ... scrivo '' in una stringa
    ELSE
        "DB_Tracking".Oven_lane_1R.Model.Name := "DB_Models_archive".Model[#Nbr].Name; // ... altrimenti, in base a #Nbr, pesco una stringa da un array e la scrivo in un altra stringa visualizzata su HMI
    END_IF;
END_IF;

 

2 ore fa, walterword ha scritto:

Dimenticavo , DB non ottimizzato

Sì, la DB non è ottimizzata

Link to post
Share on other sites
walterword

copiare una stringa in un'altra con il vecchio step 7 lo facevi carattere per carattere oppure con una funzione di copia in SCL.

Se non devi scriverci nulla nella stringa è meglio metterci degli spazi.

Dal codice sopra non capisco granchè...

Link to post
Share on other sites
Cesare Nicola

 

 

9 ore fa, walterword ha scritto:

oppure con una funzione di copia in SCL

Esatto, infatti uso SCL.

 

9 ore fa, walterword ha scritto:

Se non devi scriverci nulla nella stringa è meglio metterci degli spazi.

Sì, è quello che pensavo. Quando scrivo '' per svuotare una stringa, forse non si sa bene cosa ci viene scritto; meglio ' '.

Link to post
Share on other sites
acquaman

Scusate pensavo di rispondere per il 300 ed ho scritto una ****, ma non so come cancellare il post.🤣

Edited by acquaman
Link to post
Share on other sites
Cesare Nicola
9 minuti fa, acquaman ha scritto:

Per svuotare una stringa basta scrivere 0 nel secondo byte, nel primo byte non indicizzato c'è la lunghezza massima della striga quella impostata nella db, nel secondo byte la lunghezza reale.

Ok, grazie.

9 minuti fa, acquaman ha scritto:

Se si vuole copiare una stringa con un'altra occorre copiare carattere per carattere oppure con un moveblock e sistemare l'indice del secondo byte.

Ma se io, in SCL, faccio così  VAR1 := ' ' dove VAR1 è una variabile definita come STRING[10]  e ' ' è uno spazio compreso tra due apici, non va bene? Ho sempre pensato che così vado a scrivere un carattere nella stringa, cioè lo spazio, e dei primi due byte non me ne devo interessare.

Sono un po' confuso. Sto avendo problemi, ancora stamattina, su una cosa che faccio da sempre, non capisco. 

Link to post
Share on other sites
batta

Ho appena provato con il simulatore.

Dichiarata una variabile STRING[10], in un DB non ottimizzato per poter analizzare ogni singolo byte.

Senza fare operazioni di alcun tipo, la situazione è la seguente:

byte 0: 10 (lunghezza totale della stringa)

byte 1: 0 (lunghezza effettiva della stringa)

byte da 2 a 9: 0HEX, visualizzato '$00' come carattere.

 

Per svuotare la stringa si può scrivere

myString := '' (senza spazi).

Scrivere

myString := ' '

significa inserire un carattere spazio (20HEX, 32 Dec) che, anche se è uno spazio, è pur sempre un carattere.
Per impostare 10 spazi, si deve scrivere

myString := '          '; (10 spazi)

 

Tornando alla domanda iniziale, non ho riscontrato i problemi segnalati da Cesare Nicola

 

Link to post
Share on other sites
Cesare Nicola
3 ore fa, batta ha scritto:

Per svuotare la stringa si può scrivere

myString := '' (senza spazi).

Scrivere

myString := ' '

significa inserire un carattere spazio (20HEX, 32 Dec) che, anche se è uno spazio, è pur sempre un carattere.
Per impostare 10 spazi, si deve scrivere

myString := '          '; (10 spazi)

Esatto, è ciò che ho sempre saputo e che ho sempre fatto. Non so, mi sfugge qualcosa e ancora oggi mi è capitato. Il PLC, da codice, tramite una banale riga in SCL, non riesce a copiare StringaA in StringaB; la riga viene eseguita, con un fronte di salita, ma non accade nulla. Basta che scrivo una volta da VAT o da HMI qualcosa a caso in StringaB e da quel momento anche il PLC riesce a scriverci. Non ci sto credendo anche se lo sto vedendo. Mi viene in mente solo ora che, quando mi è capitato il problema, non ho provato a eseguire quella riga di continuo, non con fronte. Proverò. Immagino di avere un buco nel software, è l'unica spiegazione, ma non capisco proprio dove e come.

Link to post
Share on other sites
Cesare Nicola

Mi è capitato di nuovo, sempre più strano. Questo è ciò che ho fatto:

  1. Mi trovo una stringa, chiamiamola "MiaStringa "che a un certo punto è vuota, mentre il PLC dovrebbe averci scritto un valore
  2. Quando me ne accorgo, commento le righe che devono scrivere la stringa
  3. Metto un segmento SCL a inizio OB1 con una riga: "MiaStringa := 'pippo'; così com'è, senza alcuna condizione.
  4. In HMI e nella VAT, "MiaStringa continua a essere vuota. Anche in stato, nel segmento appena aggiunto, la vedo vuota, ''.
  5. Da VAT scrivo dei caratteri a caso in "MiaStringa" e da quel momento ci vedo il "pippo" che il segmento sta scrivendo
  6. Tolgo il segmento, tolgo i commenti al codice originale, tutto funziona. Fino a quando, non mi è dato sapere, finora.

Ovviamente non sono in ufficio tranquillo, ma sto avviando un impianto in Russia. 

Link to post
Share on other sites
Cesare Nicola

Mentre aspettavamo l'auto per il rientro in alloggio, in ritardo causa neve, ho scoperto una cosa che domattina modificherò sicuramente, anche se magari il problema non è quello, perché non mi piace per niente, a sensazione. Le variabili che a volte non vengono scritte, fanno parte di una struttura. In una parte di programma che trascuravo, dandola per scontata, avviene in certe situazioni un azzeramento di tutte le variabili di quella struttura, una sorta di inizializzazione della struttura. L'azzeramento è stato fatto, non da me (mi tolgo un pochino di colpa 🙂) , usando un FILL Variant a partire da una variabile INT che contiene zero:
Zero.png.7c82290de9ba3f0f3d52d310314c7042.png

Ora, cosa accade a quella povera variabile STRING, con queste istruzioni? Magari nulla, ma non mi piace: preferisco fare un MOVE di una struttura di una DB, peraltro già esistente nel progetto, identica a quella di destinazione, che abbia i valori numerici a zero e la stringa a ''.

 

E' l'unica cosa diversa che ho trovato nel progetto, rispetto a quanto facciamo normalmente quando operiamo con stringhe. Vi farò sapere, sono fiducioso.

 

Link to post
Share on other sites
walterword
Il 13/1/2021 alle 20:24 , ken ha scritto:

si usava sfc20.

si il block move in awl , io però ho sempre usato  SCL per queste cose

comunque se mystring1[30] e mystring2[30]

Se faccio mystring2:=mystring1; 

Mi funziona , scrivo e leggo dahmi senza problemi con TIA Portal V15.1.

Col vecchio step 7 la cosa era diversa facevo in questo modo , cioè ricavavo la stringa da ricercare nel DB la appoggiavo su una temporale 


                                                               BEGIN 
  
                               IF ( Cerca_Capo = true ) THEN 
                                
                                Stato_Ricerca:=0;
                                Fila_Trovata:=0;
                                Posizione_Trovata:=0;
                                app1:=Capo_Ricercato[1].Nome;
                                                               
                                FOR i:=1 TO 6 BY 1 DO 
                                      
                                      FOR j:=1 TO 6 BY 1 DO 
                                         
                                         app2:= Fila[i].Posizione[j].NOME;
                                         IF ( app2 = app1) THEN
                                        
                                               Fila_Trovata:=i;
                                               Posizione_Trovata:=j;
                                               Stato_Ricerca:=1;
                                               GOTO salta;
                                        
                                         END_IF ;     
                                                                     
                                      END_FOR;
                                   
                                END_FOR;
                                              
                              END_IF;  


                              salta:                            
                  

 

Edited by walterword
Link to post
Share on other sites
Cesare Nicola

Non ho potuto provare molto oggi, perché ho altre cosa da vedere, ma il problema sembra sparito, facendo come ho descritto nel mio ultimo messaggio. Sembra. Speriamo.

 

13 minuti fa, walterword ha scritto:

io però ho sempre usato  SCL per queste cose

Certo. A volte però i clienti ci impongono KOP perché è più comprensibile a un eventuale manutentore (e, spesso, anche ad altri programmatori). 

Link to post
Share on other sites
walterword
Il 13/1/2021 alle 20:24 , ken ha scritto:

si usava sfc20.

il cliente può imporre quello che vuole se sa quello che vuole.

Anche io faccio le logiche in ladder m uso awl solo per i driver con encoder azionamenti etc.

Ma se devo fare dei calcoli li faccio come dico io.

Puoi farti una funzione per questo scopo oppure aggiungere un segmento scl che è un linguaggio sicuramente più vicino all'essere umano e il cliente lo capirà come ha sempre fatto.

Se vuole che il suo impianto funzioni bene e subito.

Bisogna anche essere capaci di imporre e di presentare la soluzione piu chiara , semplice e veloce.

Leggere ....Stringa1:=Stringa2 è sicuramente più semplice che scrivere 2000 righe di awl o segmenti di ladder con complicazioni, scarsa manutenibilità etc

Link to post
Share on other sites
batta
16 ore fa, Cesare Nicola ha scritto:

Mentre aspettavamo l'auto per il rientro in alloggio....

Già, in Russia, purtroppo, si usa così. Nelle mie lunghe passate trasferte russe, non avere una macchina a disposizione mi pesava parecchio. D'altra parte, come guidano là, se non hai una kasko con copertura totale, è un bel rischio.

 

16 ore fa, Cesare Nicola ha scritto:

Ora, cosa accade a quella povera variabile STRING, con queste istruzioni? Magari nulla, ma non mi piace

Sinceramente, non piace nemmeno a me.
Il primo byte dovrebbe contenere la dimensione della stinga.
L'azzeramento del primo byte potrebbe benissimo essere la causa del problema. Di fatto, gli si dice che la stringa è di zero caratteri.

Una succesiva istruzione MOVE, probabilmente non reimposta la dimensione della stringa.

Una prova che potresti fare è impostare il valore del primo byte dopo il FILL, e vedere se il problema non si presenta più.

Comunque, anche se questo dovesse essere risolutivo, io eliminerei il FILL e userei un semplice MOVE scrivendo una stringa vuota, o inserendo in testo strutturato MyString := '';

Se nessuno va ad alterare la dimensione della stringa, non dovresti più avere problemi.

 

Poi non mi piace perché  l'istruzione FILL è nel gruppo "Legacy". Cerco di evitare di usare istruzioni ancora esistenti nel 1500 solo per compatibilità con i vecchi sistemi. Inoltre, ti obbliga a lavorare con DB non ottimizzati.

 

 

 

 

Link to post
Share on other sites
Cesare Nicola
6 ore fa, batta ha scritto:

Già, in Russia, purtroppo, si usa così.

No, devo dire che è stata la prima volta ieri, finora sono stati puntualissimi, anche l'anno scorso quando ero qui. Ieri le strade erano un vero disastro, non so come mai non sono passati spazzaneve, di solito passano.

 

6 ore fa, batta ha scritto:

Comunque, anche se questo dovesse essere risolutivo, io eliminerei il FILL e userei un semplice MOVE scrivendo una stringa vuota, o inserendo in testo strutturato MyString := '';

Già fatto e in effetti sembra ver risolto, anche se oggi ho potuto provare poco.
 

 

6 ore fa, batta ha scritto:

Poi non mi piace perché  l'istruzione FILL è nel gruppo "Legacy". Cerco di evitare di usare istruzioni ancora esistenti nel 1500 solo per compatibilità con i vecchi sistemi. Inoltre, ti obbliga a lavorare con DB non ottimizzati.

Condivido in toto: era stata una scelta di un collega perché sto lavorando su un software fatto a due mani.

 

 

Link to post
Share on other sites
Cesare Nicola
17 ore fa, walterword ha scritto:

Bisogna anche essere capaci di imporre e di presentare la soluzione piu chiara , semplice e veloce.

Il cliente finale al quale mi riferisco è una multinazionale nota come spaccaco.....i. Hanno richiesto nelle specifiche che il software fosse scritto "mostly" in KOP e hanno voluto verificare che davvero fosse così. Quale sia la soglia oltre la quale il software non è più "mostly KOP" dipende da come si sveglia al mattino chi te lo deve controllare. A volte ci troviamo quindi a decidere se la tal funzione sia meglio farla in KOP o SCL e a volte propendiamo per il KOP per evitare rotture di scatole. In questi mesi di sviluppo e collaudo abbiamo incontrato o ricevuto mail da decine di persone che hanno come incarico controllare una piccola parte della commessa e scrivere PDF di relazioni, tonnellate di PDF, così fan vedere che sono bravi. 

Non è sempre così facile imporre le tue scelte.

Link to post
Share on other sites
batta
15 ore fa, Cesare Nicola ha scritto:

No, devo dire che è stata la prima volta ieri, finora sono stati puntualissim

Non è per la puntualità. Di solito erano puntuali anche nel mio caso. In varie trasferte, ho passato là circa 18 mesi che, per me che non sono un trasfertista, sono tanti.
Mi riferivo al fatto di non avere un'auto a disposizione, per andare dove si vuole. Il costo dei taxi è irrisorio, ma c'è il problema della lingua: difficile trovare qualcuno che parli inglese. Anche in fabbrica avevamo le interpreti. Per andare dall'hotel in qualche posto, è semplice: ci pensano dalla reception. E poi, per tornare? Le poche volte che siamo andati in giro, il ritorno in taxi era sempre un casino. Per fortuna non ero in un posto disagiato, ma in una città, circa 500 km a sud di Mosca, da più di un milione di abitanti. Temperature? Siamo passati da -27 al oltre 40 °C. Per quanto riguarda il cibo, si mangiava bene.

Link to post
Share on other sites
walterword
Il 13/1/2021 alle 20:24 , ken ha scritto:

si usava sfc20.

La russia è un paese immenso e sconfinato. Personalmente posso dire che con noi italiani c'e' un certo rispetto. Certo bisogna sempre stare attenti perche dopo il terzo litro di vodka qualcuno di loro potrebbe rievocare i fantasmi del passato e magari aggredirti. Mi sono trovato meglio in Iran. Anche in Brasile, argentina, india ci sono località remote. Beh ho sempre cercato di farmi gli affari miei e starmene li in guethouse oppure in albergo. Girare in posti dove non sai mai cosa potrebbe capitarti, con chi e perchè non è bello. Sei sempre un ospite, almeno io la vedo cosi.

Link to post
Share on other sites
walterword
10 ore fa, Cesare Nicola ha scritto:

Il cliente finale al quale mi riferisco è una multinazionale nota come spaccaco.....i. Hanno richiesto nelle specifiche che il software fosse scritto "mostly" in KOP e hanno voluto verificare che davvero fosse così. Quale sia la soglia oltre la quale il software non è più "mostly KOP" dipende da come si sveglia al mattino chi te lo deve controllare. A volte ci troviamo quindi a decidere se la tal funzione sia meglio farla in KOP o SCL e a volte propendiamo per il KOP per evitare rotture di scatole. In questi mesi di sviluppo e collaudo abbiamo incontrato o ricevuto mail da decine di persone che hanno come incarico controllare una piccola parte della commessa e scrivere PDF di relazioni, tonnellate di PDF, così fan vedere che sono bravi. 

Non è sempre così facile imporre le tue scelte.

Ma si che problema c'e' ? Si fa presente che con 3 righe di SCL , chiaro ed umano , si può risolvere un problema che diversamente sarebbe più complicato e difficile da manutenere. SI propone, si dialoga , si parla. Sappiamo tutti benissimo che i vari capetti, project manager, capi architetti dell'automazione sono dei poveri stupidi falliti che non sanno nemmeno accendere una lampadina e lo sanno bene anche loro. Ci vuole tatto e tecnica 😉 

Ho girato anche io mezzo mondo, per Techint-Italimpianti, Tenova, etc etc etc impianti da qualche milione di euro. Ho visto anche io svariati dementi che venivano sul impianto col cronometro, i fogli e le cazzate ....ma tante cazzate.....facevo finta di ascoltarli , li compiacevo, parlavo con il loro boss e spiegavo con poche parole le mie idee ed intenzioni.

Il problema non sono loro ma quelli che hai alle spalle che dovrebbero proteggerti e tutelarti ossia i soliti venditori e pagliacci italiani che pur di vendere raccontano balle a non finire e non finiranno mai le balle. Se l'automazione italiana vende e lavora è solo perche siamo molto malleabili nei confronti del cliente finale,ci arrabbiamo , cacciamo 4 bestemmie e poi troviamo la soluzione sempre ed ovunque. I tedeschi e gli inglesi non sono cosi, ma loro possono permetterselo perchè sono organizzati , non dico più capaci, ma hanno la carta e la gente che parla per un tecnico. Noi siamo un paese di disperati che cercano di andare avanti ....la storia dovrebbe insegnartelo, senza andare troppo lontano, basta solo il secolo scorso. 

 

Edited by walterword
Link to post
Share on other sites
batta
1 ora fa, walterword ha scritto:

I tedeschi e gli inglesi non sono cosi, ma loro possono permetterselo perchè sono organizzati

Qualche volta sono anche più organizzati, ma altre no.

Spesso non sono più organizzati, sono solo più rigidi, che è diverso.

 

 

 

Link to post
Share on other sites
Cesare Nicola
3 ore fa, walterword ha scritto:

Se l'automazione italiana vende e lavora è solo perche siamo molto malleabili nei confronti del cliente finale,ci arrabbiamo , cacciamo 4 bestemmie e poi troviamo la soluzione sempre ed ovunque. I tedeschi e gli inglesi non sono cosi, ma loro possono permetterselo perchè sono organizzati , non dico più capaci, ma hanno la carta e la gente che parla per un tecnico. Noi siamo un paese di disperati che cercano di andare avanti ....la storia dovrebbe insegnartelo, senza andare troppo lontano, basta solo il secolo scorso

Sembra retorica, ma mi sento di darti ragione, perlomeno se guardo alla mia recente esperienza con questa multinazionale che tanto mi piacerebbe citare... 😀 Tu sei lì, da solo, a cercare di far funzionare un impianto grosso due volte casa tua, con le tue capacità che nel mio caso non sono chissachè, e loro arrivano in sei, sette otto, fino a dodici ne ho contati, per vedere se la brugola da 8x30 è brunita o zincata. Ho visto gente aggirarsi attorno all'impianto che nemmeno si è tolta il giubbotto, per dire quanto fosse impegnata (e non faceva freddo). Uno, alle 11.30, mi ha chiesto "fermiamoci un attimo perché sono stanco". Poveretto, stavamo analizzando l'HMI, lavoro notoriamente sfiancante. Stanco? Ah, perché, sul lavoro si può anche essere stanchi alle 11.30? Poi ti dicono "ma non hai letto il PDF"? No, porca zozza, non l'ho letto perché me ne avete inviati 4138 negli ultimi 4 mesi ma nel frattempo io stavo cercando di far funzionare un impianto secondo le vostre bislacche idee, consapevole che una parte del lavoro dovrò buttarlo perché prima o poi si capirà che era insensato.

Fine dello sfogo, scusatemi. 

Link to post
Share on other sites
drn5
5 ore fa, batta ha scritto:

Spesso non sono più organizzati, sono solo più rigidi

Parole sante.

 

7 ore fa, walterword ha scritto:

Noi siamo un paese di disperati che cercano di andare avanti

Già. Passano gli anni, ma spesso, troppo spesso le cose non cambiano. Se avessimo l'organizzazione tedesca con la nostra inventiva saremmo già su Marte.

 

Un'altra cosa che ci fa andare forte è che non molliamo. Le sfide, ho sempre trovato gente che non si tira indietro.

Link to post
Share on other sites
walterword
Il 13/1/2021 alle 20:24 , ken ha scritto:

si usava sfc20.

Mi sono ritrovato più volte con dispositivi semplici come accoppiatori di encoder  all'asse dedicato fuori asse di parecchi mm. In Germania , ma non solo, avevo risolto tagliando un pezzo della canna da innaffiare, gommosa, e col filo di ferro avevo accoppiato gli encoders ai vari assi. Per lo stesso problema, gli anglosassoni sarebbero arrivati in 5-6 figure, con laser, strumenti per capire, ragionare, riprogettare. La nostra storia ce lo insegna da parecchi secoli. Ma ora nel tempo della grande tecnologia gli arrangiamenti non servono a nulla. Bisogna progettare, testare ed arrivare sul cantieri più preparati , c'è poco da fare. Questa cosa i project manager, gli imprenditori e i venditori italiani non l'hanno ancora capita, la cosa inizia ad essere fuori tempo e fuori gestione. Il denaro non manca e nemmeno la struttura. Ma i nostri imprenditori preferiscono buttare nel cesso denaro, tempo e risorse per le solite caxxate senza senso che vorrebbero far piacere al cliente....solo che al cliente le stupidate non piacciono e quando firma un contratto con gli italiani sa già come fare, cosa pretendere, quanto rosicare ed in molti casi si mangiano interi impianti con penali e mancato guadagno. Poi tu che sei il programmatore sei là e dovresti , problem solving, risolvere tutto ma non è sempre cosi.

 

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...