Jump to content

Routine to copy data from one ATTRIBUTE to another?


lamensterms

Recommended Posts

Hey guys,

 

I have 2 'ATTRIBUTE' blocks which i would like to copy data from fields in one block to fields (of different names/tags) in the other block.

 

I would normally try and have a crack at developing this routine myself... but im afraid i have absolutely no idea where to begin on this one.

 

I have attached a .DWG with the two blocks and some leaders indicating the direction, source and destination i would like to copy.

 

If someone could please help me get the ball rolling on this one it would be greatly appreciated.

 

Thank you.

 

ps: im afraid the formatting of each ATTRIBUTE cannot be modified - it is all setup by a 3rd party addon package.

 

BLOCK ATTRIBUTES.dwg

Link to comment
Share on other sites

I poted a VBA soloution a long time ago that allows you to pick a block and then amend another block based on parameters from the first block what a mouthfull. if you want it post here. It does what you want.

 

Anyway any of the block edit routines by say Lee or Alanjt could be modified pretty easy to handle two blocks, just need to use the code basicly twice. Pick 1st block pick 2nd block or in my case I know second block exists only once in dwg so can be found.

Link to comment
Share on other sites

thanks for the reply BIGAL.

 

Could you please post a link to the VBA solution you have?

 

Also, could you please point me in the direction of LEE and ALANJTs block edit routines?

 

thanks again mate.

Link to comment
Share on other sites

thanks for the reply Lee - i kinda managed to get it half working, i modified your routine from here... http://www.cadtutor.net/forum/showthread.php?32085-Need-Lisp-to-update-attributes.

 

by replacing the two original source tags with two of my source tags, and also replacing the two original destination tags with two of my destination tags... it did work.

 

(defun c:blkupd     (/ bEnt aEnt eLst aGRIP aLENGTH aQTY aLOC ss EntLst attEnt attEntLst)
 (if (and (setq bEnt (car (entsel "\nSelect Block to Retrieve Attribute Values >   ")))
      (= "INSERT" (cdadr (entget bEnt))) (= 1 (cdr (assoc 66 (entget bEnt)))))
   (progn
     (setq aEnt (entnext bEnt))
     (while (= "ATTRIB" (cdadr (setq eLst (entget aEnt))))
   (cond ((= "FNUMX" (cdr (assoc 2 eLst)))
          (setq aGRIP (cdr (assoc 1 eLst))))
         ((= "FLENX" (cdr (assoc 2 eLst)))
          (setq aLENGTH (cdr (assoc 1 eLst)))))
   (setq aEnt (entnext aEnt)))
     (if (and aGRIP aLENGTH)
   (progn
     (if (setq ss (ssget (list (cons 0 "INSERT")(cons 66 1)
       (if    (getvar "CTAB")(cons 410 (getvar "CTAB")) (cons 67 (- 1 (getvar "TILEMODE")))))))
       (progn
         (setq EntLst (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss))))
         (foreach e  EntLst
       (setq attEnt (entnext e))
       (while (= "ATTRIB" (cdadr (setq attEntLst (entget attEnt))))
         (cond    ((= "PDCGRIP" (cdr (assoc 2 attEntLst)))
            (entmod (subst (cons 1 aGRIP) (assoc 1 attEntLst) attEntLst)))
           ((= "PDCLENGTH" (cdr (assoc 2 attEntLst)))
            (entmod (subst (cons 1 aLENGTH) (assoc 1 attEntLst) attEntLst))))
         (setq attEnt (entnext attEnt)))))
       (princ "\n<!> No Blocks Selected <!>")))
   (princ "\n<!> Selected Block Doesn't Contain Required Attributes <!> ")))
   (princ "\n<!> No Block Selected <!>"))
 (command "_regenall")
 (princ))

 

but when i added the addition tags i need replaced... i get an "error: no function definition: ".

 

(defun c:bl     (/ bEnt aEnt eLst aGRIP aLENGTH aQTY aLOC ss EntLst attEnt attEntLst)
 (if (and (setq bEnt (car (entsel "\nSelect Block to Retrieve Attribute Values >   ")))
      (= "INSERT" (cdadr (entget bEnt))) (= 1 (cdr (assoc 66 (entget bEnt)))))
   (progn
     (setq aEnt (entnext bEnt))
     (while (= "ATTRIB" (cdadr (setq eLst (entget aEnt))))
   (cond ((= "FNUMX" (cdr (assoc 2 eLst)))
          (setq aGRIP (cdr (assoc 1 eLst))))
         ((= "FLENX" (cdr (assoc 2 eLst)))
          (setq aLENGTH (cdr (assoc 1 eLst)))))
         ((= "FQTYX" (cdr (assoc 2 eLst)))
          (setq aQTY (cdr (assoc 1 eLst)))))
         ((= "FREMARKX" (cdr (assoc 2 eLst)))
          (setq aLOC (cdr (assoc 1 eLst)))))
   (setq aEnt (entnext aEnt)))
     (if (and aGRIP aLENGTH aQTY aLOC)
   (progn
     (if (setq ss (ssget (list (cons 0 "INSERT")(cons 66 1)
       (if    (getvar "CTAB")(cons 410 (getvar "CTAB")) (cons 67 (- 1 (getvar "TILEMODE")))))))
       (progn
         (setq EntLst (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss))))
         (foreach e  EntLst
       (setq attEnt (entnext e))
       (while (= "ATTRIB" (cdadr (setq attEntLst (entget attEnt))))
         (cond    ((= "PDCGRIP" (cdr (assoc 2 attEntLst)))
            (entmod (subst (cons 1 aGRIP) (assoc 1 attEntLst) attEntLst)))
           ((= "PDCLENGTH" (cdr (assoc 2 attEntLst)))
            (entmod (subst (cons 1 aLENGTH) (assoc 1 attEntLst) attEntLst))))
           ((= "PDCQTY" (cdr (assoc 2 attEntLst)))
            (entmod (subst (cons 1 aQTY) (assoc 1 attEntLst) attEntLst))))
           ((= "PDCLOCATION" (cdr (assoc 2 attEntLst)))
            (entmod (subst (cons 1 aLOC) (assoc 1 attEntLst) attEntLst))))
         (setq attEnt (entnext attEnt)))))
       (princ "\n<!> No Blocks Selected <!>")))
   (princ "\n<!> Selected Block Doesn't Contain Required Attributes <!> ")))
   (princ "\n<!> No Block Selected <!>"))
 (command "_regenall")
 (princ))

 

ive been through the code a couple of times... but i think it is a little too sophisticated for me to be able to identify the issue.

 

Also... is there a way to extract only some data from each field. for instance if i have a field which contains AAA bbb CCC 7638... is is possible to distribute a portion on that entry into multiple fields. AAA to a field 1 and CCC to field 2, etc.

 

 

thanks again for any help.

Link to comment
Share on other sites

Re your AA bb CCC 7638 I had a search just had to find it (vl-string-search "CCC" str) this will search a string for a match. Also if the text is always space delimeted or any character theres a good LEE Mac example floating around here will see if I can find.

Link to comment
Share on other sites

thanks again for the reply BIGAL - but the string to be separated will not always be the same, so the string match will not work. however... the text will always be space delimited. so LEEs routines may again be applicable.

 

here is an example of what i require....

 

The application i have for this routine is for the transfer of bolt information from an overall summary to a more specific table format. So i wish to extract the SIZE, LENGTH and GRADE information from the NAME.

so the name of a bolt (as it appears in the summary) could be M24 x 50 8.8/TB GALV - and the extracted information would be as follows: SIZE = M24, LENGTH = 50 and GRADE = 8.8/TB.

 

thanks again.

Link to comment
Share on other sites

The application i have for this routine is for the transfer of bolt information from an overall summary to a more specific table format. So i wish to extract the SIZE, LENGTH and GRADE information from the NAME.

so the name of a bolt (as it appears in the summary) could be M24 x 50 8.8/TB GALV - and the extracted information would be as follows: SIZE = M24, LENGTH = 50 and GRADE = 8.8/TB.

 

One possible way to accomplish this element of the task would be to use a parser such as my str->lst function from here, used in the following way:

 

(LM:str->lst "M24 x 50 8.8/TB GALV" " ")

("M24" "x" "50" "8.8/TB" "GALV")

Link to comment
Share on other sites

Thanks for the reply lee. But can you please demonstrate how to incorporate that into the routine I posted above? Also... How can I add extra tags to detect (explained in earlier post)?

Link to comment
Share on other sites

Not to take away from Lee a bit more help with his code

 

(setq attrib "M24 x 50 8.8/TB GALV") ;  you would normally return a value here that is the attribute value but for testing purposes preset attrib

(setq ans (LM:str->lst attrib " "))
(setq howmany (length ans))   ; the total number of items

; do a loop here say using repeat you can use while or if VL foreach
(setq x 0)
(repeat howmany
((setq whatis (nth x ans))   ;use the nth function to retrieve the values
(princ whatis)   ; do something with this now (nth 0 ans) is "M24" (nth 1 ans ) is "x" and so on
(setq x (+ x 1)) ; increment x for next item in list
)

Link to comment
Share on other sites

Thanks again for the reply bigal. I'm still struggling to understand the philosophy. I think it's just over my head.

 

If I can get the multiple tags (more than 2) to work... That should be sufficient for now.

 

Cheers mate - cats got the tigers this weekend ey? Should be easy enough.

Link to comment
Share on other sites

  • 1 year later...

Hi guys...

 

So after over a year, I'm finally getting around to revisiting this...

 

I have a version of the code below - which does not work...

 

;;-------------------=={ String to List }==-------------------;;
;;                                                            ;;
;;  Separates a string into a list of strings using a         ;;
;;  specified delimiter string                                ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  str - string to process                                   ;;
;;  del - delimiter by which to separate the string           ;;
;;------------------------------------------------------------;;
;;  Returns:  A list of strings                               ;;
;;------------------------------------------------------------;;

(defun LM:str->lst ( str del / pos lst )
   (while (setq pos (vl-string-search del str))
       (setq lst (cons (substr str 1 pos) lst) 
             str (substr str (+ pos 1 (strlen del)))
       )
   )
   (reverse (cons str lst))
) 


;-----------BOLT LIST---------------------------


(defun c:bl     (/ bEnt aEnt eLst aGRI aLOC aLEN aQTY ss EntLst attEnt attEntLst)
 (if (and (setq bEnt (car (entsel "\nSelect Block to Retrieve Attribute Values >   ")))
      (= "INSERT" (cdadr (entget bEnt))) (= 1 (cdr (assoc 66 (entget bEnt)))))
   (progn
     (setq aEnt (entnext bEnt))
     (while (= "ATTRIB" (cdadr (setq eLst (entget aEnt))))
   (cond ((= "FNUMX" (cdr (assoc 2 eLst)))
          (setq aGRI (cdr (assoc 1 eLst))))
         ((= "FREMARKX" (cdr (assoc 2 eLst)))
          (setq aLOC (cdr (assoc 1 eLst))))
         ((= "FLENX" (cdr (assoc 2 eLst)))
          (setq aLEN (cdr (assoc 1 eLst))))
         ((= "FQTYX" (cdr (assoc 2 eLst)))
          (setq aQTY (cdr (assoc 1 eLst))))
         ((= "FDESCMX" (cdr (assoc 2 eLst)))
          (setq aDECS (cdr (assoc 1 eLst))))
        
(setq attrib aDECS)
(setq ans (LM:str->lst attrib " "))
(setq aDIAM (nth 0 ans))
(setq aTYPE (nth 3 ans))
)

   (setq aEnt (entnext aEnt)))
     (if (and aGRI aLOC aLEN aQTY)
   (progn
     (if (setq ss (ssget ":S" (list (cons 0 "INSERT")(cons 66 1)
       (if    (getvar "CTAB")(cons 410 (getvar "CTAB")) (cons 67 (- 1 (getvar "TILEMODE")))))))
       (progn
         (setq EntLst (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss))))
         (foreach e  EntLst
       (setq attEnt (entnext e))
       (while (= "ATTRIB" (cdadr (setq attEntLst (entget attEnt))))
         (cond    ((= "PDCGRIP" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aGRI) (assoc 1 attEntLst) attEntLst)))
                  ((= "PDCLOCATION" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aLOC) (assoc 1 attEntLst) attEntLst)))
                  ((= "PDCLENGTH" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aLEN) (assoc 1 attEntLst) attEntLst)))
                  ((= "PDCQTY" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aQTY) (assoc 1 attEntLst) attEntLst)))

                  ((= "PDCDIA" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aDIAM) (assoc 1 attEntLst) attEntLst)))

                  ((= "PDCTYPE" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aTYPE) (assoc 1 attEntLst) attEntLst)))
         )
         (setq attEnt (entnext attEnt)))))
       (princ "\n<!> No Blocks Selected <!>")))
   (princ "\n<!> Selected Block Doesn't Contain Required Attributes <!> ")))
   (princ "\n<!> No Block Selected <!>"))
 (command "_regenall")
 (princ)
)

 

Which I cannot get to work (error: bad DXF group: (1)) - I'll keep looking at it, but I thought perhaps I'd show you guys and hopefully you can pick something up...

 

Thanks again for all your help.

 

Cheers.

Link to comment
Share on other sites

Hi Lee,

 

Thanks for taking the time to help.

 

I’ve made a few modifications to the routine (highlighted BOLD below), but I am now getting a different error (; error: bad argument type: (or stringp symbolp): nil) – which is suggesting to me that the ATTRIB and ADECS variables are not strings.

 

;;-------------------=={ String to List }==-------------------;;
;;                                                            ;;
;;  Separates a string into a list of strings using a         ;;
;;  specified delimiter string                                ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  str - string to process                                   ;;
;;  del - delimiter by which to separate the string           ;;
;;------------------------------------------------------------;;
;;  Returns:  A list of strings                               ;;
;;------------------------------------------------------------;;

(defun LM:str->lst ( str del / pos lst )
   (while (setq pos (vl-string-search del str))
       (setq lst (cons (substr str 1 pos) lst) 
             str (substr str (+ pos 1 (strlen del)))
       )
   )
   (reverse (cons str lst))
) 



;-----------BOLT LIST---------------------------


(defun c:bl     (/ bEnt aEnt eLst aGRI aLOC aLEN aQTY ss EntLst attEnt attEntLst ans attrib aDECS aDIAM aTYPE)
 (if (and (setq bEnt (car (entsel "\nSelect Block to Retrieve Attribute Values >   ")))
      (= "INSERT" (cdadr (entget bEnt))) (= 1 (cdr (assoc 66 (entget bEnt)))))
   (progn
     (setq aEnt (entnext bEnt))
     (while (= "ATTRIB" (cdadr (setq eLst (entget aEnt))))
   (cond ((= "FNUMX" (cdr (assoc 2 eLst)))
          (setq aGRI (cdr (assoc 1 eLst))))
         ((= "FREMARKX" (cdr (assoc 2 eLst)))
          (setq aLOC (cdr (assoc 1 eLst))))
         ((= "FLENX" (cdr (assoc 2 eLst)))
          (setq aLEN (cdr (assoc 1 eLst))))
         ((= "FQTYX" (cdr (assoc 2 eLst)))
          (setq aQTY (cdr (assoc 1 eLst))))
         ((= "FDESCMX" (cdr (assoc 2 eLst)))
          (setq aDECS (cdr (assoc 1 eLst))))
    [b])[/b]
(setq attrib aDECS)
(setq ans (LM:str->lst attrib " "))
(setq aDIAM (nth 0 ans))
(setq aTYPE (nth 3 ans))


   (setq aEnt (entnext aEnt)))
     (if (and aGRI aLOC aLEN aQTY [b]aDECS[/b])
   (progn
     (if (setq ss (ssget ":S" (list (cons 0 "INSERT")(cons 66 1)
       (if    (getvar "CTAB")(cons 410 (getvar "CTAB")) (cons 67 (- 1 (getvar "TILEMODE")))))))
       (progn
         (setq EntLst (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss))))
         (foreach e  EntLst
       (setq attEnt (entnext e))
       (while (= "ATTRIB" (cdadr (setq attEntLst (entget attEnt))))
         (cond    ((= "PDCGRIP" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aGRI) (assoc 1 attEntLst) attEntLst)))
                  ((= "PDCLOCATION" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aLOC) (assoc 1 attEntLst) attEntLst)))
                  ((= "PDCLENGTH" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aLEN) (assoc 1 attEntLst) attEntLst)))
                  ((= "PDCQTY" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aQTY) (assoc 1 attEntLst) attEntLst)))

                  ((= "PDCDIA" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aDIAM) (assoc 1 attEntLst) attEntLst)))

                  ((= "PDCTYPE" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aTYPE) (assoc 1 attEntLst) attEntLst)))
         )
         (setq attEnt (entnext attEnt)))))
       (princ "\n<!> No Blocks Selected <!>")))
   (princ "\n<!> Selected Block Doesn't Contain Required Attributes <!> ")))
   (princ "\n<!> No Block Selected <!>"))
 (command "_regenall")
 (princ)
)

 

If the CDR function returns a LIST (ATTRIB and ADECS are LISTS?)… do I need to convert these single item LISTS to STRINGS then convert these STRINGS into multiple item LISTS delimited by space (“ “)? If so… how would you suggest this be done?

 

Haha, as you can probably tell – I’m wading through unfamiliar waters.

 

Thanks again Lee.

 

Cheers.

Link to comment
Share on other sites

cdadr ??? should this be caddr

 

Whilst this may seem a big change I would look at the sample code posted here on Forum previously for VL for doing this task its a lot easier to use you dont worry about stuff like assoc 66 and entnext VL has lots of advantages in asking for a property as a single english question rather than using assoc's.

 

The while becomes a foreach and steps through the attributes you can use either a tag name or its logical order in the block.

 

example code cut from a bigger program this replaces around 7 attributes in multiple layout title blocks
(setq ss1 (ssget "x"  (list (cons 0 "INSERT") (cons 2 bname)(cons 410 tabname))))
(foreach att (vlax-invoke (vlax-ename->vla-object (ssname SS1 J )) 'getattributes)  ; loop through blocks add 1 to J
       (if (= oldtag6 (strcase (vla-get-tagstring att)))  ; put your cond here with multiple tags replacing oldtag6
       (setq newstr6 (vla-get-textstring att)) 
       )
     )

Link to comment
Share on other sites

Hi BIGAL,

 

Thanks for the reply.

 

Not sure about CDADR vs CADDR as the original code is adapted from this thread and is not my own.

 

I believe I have found the source of the error, I had the following code:

 

(setq attrib aDECS)
(setq ans (LM:str->lst attrib " "))
(setq aDIAM (nth 0 ans))
(setq aTYPE (nth 3 ans))

 

... in the wrong place.

 

Please see below code for what seems to be a complete working version (with a few other adjustments)...

 

;;-------------------=={ String to List }==-------------------;;
;;                                                            ;;
;;  Separates a string into a list of strings using a         ;;
;;  specified delimiter string                                ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  str - string to process                                   ;;
;;  del - delimiter by which to separate the string           ;;
;;------------------------------------------------------------;;
;;  Returns:  A list of strings                               ;;
;;------------------------------------------------------------;;

(defun LM:str->lst ( str del / pos lst )
   (while (setq pos (vl-string-search del str))
       (setq lst (cons (substr str 1 pos) lst) 
             str (substr str (+ pos 1 (strlen del)))
       )
   )
   (reverse (cons str lst))
) 



;-----------BOLT LIST---------------------------


(defun c:bl     (/ bEnt aEnt eLst aGRI aLOC aLEN aQTY ss EntLst attEnt attEntLst ans attrib aDECS aDIAM aTYPE)
 (if (and (setq bEnt (car (entsel "\nSelect Block to Retrieve Attribute Values >   ")))
      (= "INSERT" (cdadr (entget bEnt))) (= 1 (cdr (assoc 66 (entget bEnt)))))
   (progn
     (setq aEnt (entnext bEnt))
     (while (= "ATTRIB" (cdadr (setq eLst (entget aEnt))))
   (cond ((= "FNUMX" (cdr (assoc 2 eLst)))
          (setq aGRI (cdr (assoc 1 eLst))))
         ((= "FREMARKX" (cdr (assoc 2 eLst)))
          (setq aLOC (cdr (assoc 1 eLst))))
         ((= "FLENX" (cdr (assoc 2 eLst)))
          (setq aLEN (cdr (assoc 1 eLst))))
         ((= "FQTYX" (cdr (assoc 2 eLst)))
          (setq aQTY (cdr (assoc 1 eLst))))
         ((= "FDESCMX" (cdr (assoc 2 eLst)))
          (setq aDECS (cdr (assoc 1 eLst))))
    )




   (setq aEnt (entnext aEnt)))



(setq aGRI2 (SUBSTR aGRI 2 2))

(setq attrib aDECS)
(setq ans (LM:str->lst attrib " "))
(setq aDIAM (nth 0 ans))
(setq aTYPE (nth 3 ans))




     (if (and aGRI aLOC aLEN aQTY aDECS)
   (progn
     (if (setq ss (ssget ":S" (list (cons 0 "INSERT")(cons 66 1)
       (if    (getvar "CTAB")(cons 410 (getvar "CTAB")) (cons 67 (- 1 (getvar "TILEMODE")))))))
       (progn
         (setq EntLst (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss))))
         (foreach e  EntLst
       (setq attEnt (entnext e))
       (while (= "ATTRIB" (cdadr (setq attEntLst (entget attEnt))))
         (cond    ((= "PDCGRIP" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aGRI2) (assoc 1 attEntLst) attEntLst)))
                  ((= "PDCLOCATION" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aLOC) (assoc 1 attEntLst) attEntLst)))
                  ((= "PDCLENGTH" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aLEN) (assoc 1 attEntLst) attEntLst)))
                  ((= "PDCQTY" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aQTY) (assoc 1 attEntLst) attEntLst)))

                  ((= "PDCDIA" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aDIAM) (assoc 1 attEntLst) attEntLst)))

                  ((= "PDCTYPE" (cdr (assoc 2 attEntLst)))
                   (entmod (subst (cons 1 aTYPE) (assoc 1 attEntLst) attEntLst)))
         )
         (setq attEnt (entnext attEnt)))))
       (princ "\n<!> No Blocks Selected <!>")))
   (princ "\n<!> Selected Block Doesn't Contain Required Attributes <!> ")))
   (princ "\n<!> No Block Selected <!>"))
 (command "_regenall")
 (princ)
)

 

Thanks again.

Link to comment
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.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  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...