Jump to content

BoA Editor Remake


Recommended Posts

Awesome, but your links are messed up. The first goes to the file releases page and the second goes to the webpage.

 

As of now I think that's all we need, but I believe it is required to put Sourceforge's logo somewhere on the site. It should indicate that the site is hosted by SourceForge, and should link to SourceForge.net.

 

Any ideas for content are welcome.

 

EDIT: For clarity, I meant the links on your post. Sorry for any confusion.

EDIT: Nevermind about the links.

 

EDIT:

Quote:
but I cannot figure out how to put other controls on notebook view.
Me neither. We'll probably have to do that part by hand, if we need it.
Link to comment
Share on other sites

  • Replies 168
  • Created
  • Last Reply

Top Posters In This Topic

Kelandon

Nice Top page.

Isn't it better to add Louvre to the link part?

Quote:
And what makes an item "registered"?
The lower part of the palette works to "register/unregister" items.

When "register" button is pushed, selected item is registered to the "registered list".

Select one line of "registered list" and push "delete" button, then the item is removed form "registered list".

 

Umm.. this interface seems not to be intuitive. I'll make another plan.

Link to comment
Share on other sites

Quote:
Originally written by Notus:

Umm.. this interface seems not to be intuitive. I'll make another plan.
Perhaps we should port the current code to wxWidgets first. Actually, I don't think we have to do this in order to use controls made through wxWidgets, but it would be cleaner.

As for the palette, I hope the code generators I found will help.
Link to comment
Share on other sites

Quote:
KernelKnowledge12 wrote
Perhaps we should port the current code to wxWidgets first.
We should absolutely port the current code to wxWidgets, so I proposed to modularize the current code.

But as for the user interface design, it isn't necessary to port the code right now. What we are doing now is a test to examine how easily user can realize the function we'll implement, from a picture of user interface.

I used "Interface Builder" on Xcode to draw the first plan, but it doesn't mean we use it for the actual code. I used "Interface Builder" as a picture drawing application. If I drew it on Windows, I would use Visual BASIC as a picture drawer.
I took care to use as many parts that wxWidgets has similar one as I can. Only exception is the icon display, Mac uses PICT and Win uses BMP.

Quote:
KernelKnowledge12 wrote
I found two more IDE type programs that might help us.
wxhatch
FireGUI
OK, I'll try.
Link to comment
Share on other sites

Another palette design. I showed Mac version, Windows version will have also almost the same appearance.

 

Palette design plan 2

Four independent palettes for Floor, Terrain, Item and Creature. And another "My Palette", customizable palette.

 

P2menu.jpg

 

The appearance of Four independent palettes is as follows. This example shows "Item" palette, other palettes are similar to this palette. Only icon size is different.

 

P2ItemPalette.jpg

 

"My Palette" is customizable one. It can contain different type icons in one panel. To add an icon, drag the icon from each independent palette to this panel.

 

P2MyPalette.jpg

 

The explanation of palette function.

 

P2ItemPaletteExp.jpg

 

P2MyPaletteExp.jpg

 

Also you can import/export "My Collection", a setting of one panel, as a file to exchange it with other users.

 

[Edit]

Added "My Collection" feature.

Link to comment
Share on other sites

Notus -

I figured out what we were doing wrong with wxGlade. All controls must go on a sizer control. The notebook control went on the sizer that was automatically created by the wxFrame control, but since the notebook's pane did not have one, you couldn't put any controls on. To put controls on the notebook view, first add a sizer (there are two kinds of these.)

Link to comment
Share on other sites

If I may suggest something:

Make the editor a fairly basic framework. Perhaps the "base editory" would be even less functional then the current BoA Editor. Then, each imporvement could be worked in as a "module," "plugin" or "expansion." For the sake of simplicity, I'll just call them "plugins" for now.

 

So, you could have a plugin which modifies the terrain display window(s) to allow for switching between 3D and 2D editing.

 

I would aim for basic framework functionality of the following:

· Numeric pallettes for floors, terrains, and items

· On screen editing for hights

· Scallable editing are

· Menu access to all the current commands

· Communication pathways (vestigal)

· Scripting options (vestigal)

The two "vestigal" pieces would be built in for future plugins to use. For example, the whole copy/paste bit and the internet access to databases would use the communications pathways, while the scripting options could work through plugins to allow for in-line scripts of all sorts, as well as interfaces for new terrain and items editors.

 

Key plugins would then include:

· Button-selectible pallettes

· More pallettes for town options, and similar

· Echoing some menu items in pre-existing palletts

· A 3D editing option

· An in-line dialogue editor

· An in-line script editor

· An in-line object editor (ie new objects, floors, terrains, etc.)

· Communications with online databases

· In-line access to BoA for testing

Etc.

Link to comment
Share on other sites

Quote:
Originally written by Dastal:
If I may suggest something:
Make the editor a fairly basic framework. Perhaps the "base editory" would be even less functional then the current BoA Editor. Then, each imporvement could be worked in as a "module," "plugin" or "expansion."
This is the ultimate goal of the project. We are not starting by doing this, because it could lead to complications that will delay a release. Notus convinced me of this, and he will be able to better explain this approach.

As for plugins, we will by the end try to support a scripting engine that parallels straight C, since Avernum Script does too. For now, however, our goal is to help the BoA editors create scenarios in a simpler and easier way. Once this is achieved to an acceptable level, we'll try to significantly expand our editor.

Thank you for all your suggestions.

Also, from reading what you wrote, it seems as though you have some programming experience. If your willing to help on a programming level, please say so.

Also:

Your very last suggestion may be impossible, but we should be able to provide a similar feature by the end.

EDIT:

Quote:
Originally written by Dahak:

One tiny little thing to be added that would be most useful. The default editor has a "Make all items NOT property" option, but no "Make all items property" option. This under the town menu.
This could be done fairly quickly, but there seems to be something wrong with SourceForge's CVS server. It might be a while before this gets fixed.

EDIT:
About five minutes after editing this post the first time, the CVS server started working. Second time something like this has happenend confused .
Link to comment
Share on other sites

I've been thinking for a little while, and I have come up with an admittedly crude design for the modularization of this project.

 

Proposed Modularization:

 

  • kernel

    </font><ul type="square">

  • <font size="2" face="Verdana, Arial, Helvetica, sans-serif">
  • structures

    </font><ul type="square">

  • <font size="2" face="Verdana, Arial, Helvetica, sans-serif">
  • core game data
  • .bas file data

</font></li>

[*]algorithms

[*]scripting(*)

  • <font size="2" face="Verdana, Arial, Helvetica, sans-serif">avernum script scripting

    </font><ul type="square">

  • <font size="2" face="Verdana, Arial, Helvetica, sans-serif">
  • parser
  • debugger

</font></li>

[*]editor scripting

  • <font size="2" face="Verdana, Arial, Helvetica, sans-serif">virtual machine
  • parser/compiler
  • primitives

</font></li></ul><font size="2" face="Verdana, Arial, Helvetica, sans-serif"></font></li></ul><font size="2" face="Verdana, Arial, Helvetica, sans-serif"></font></li>

[*]gui

  • <font size="2" face="Verdana, Arial, Helvetica, sans-serif">main menu

    </font><ul type="square">

  • <font size="2" face="Verdana, Arial, Helvetica, sans-serif">
  • file, view, etc.

</font></li>

[*]views

  • <font size="2" face="Verdana, Arial, Helvetica, sans-serif">terrain view
  • core game data view
  • dialog based views

    </font><ul type="square">

  • <font size="2" face="Verdana, Arial, Helvetica, sans-serif">
  • town data view, wandering view etc.

</font></li></ul><font size="2" face="Verdana, Arial, Helvetica, sans-serif"></font></li>

[*]toolbars

[*]package manager (*)</ul><font size="2" face="Verdana, Arial, Helvetica, sans-serif"></font></li>

[*]database communications (*)</ul><font size="2" face="Verdana, Arial, Helvetica, sans-serif">This is by no means complete. I await any suggestions/thoughts on this.

(*) Items marked with this need much more consideration.

Link to comment
Share on other sites

KernelKnowledge12,

Quote:
This is by no means complete.
It's OK. We always make applications from the middle, neither top down nor bottom up.

 

There are many criteria to modularize the application.

In this case, our purpose of modularization is,

- Split down current 3D editor code and insert them into wxWidget framework.

- Isolate modules each other to remake them individually.

 

I think we will need to reconsider the classification of modules once more in the course of development. And it will be a form as you suggested.

But now, we need some work bench to test and makeup our objects.

Let's practice.

1. Using wxGlade, make an application with a wxFrame

2. Add menubar to wxFrame (Widget tab - "Has MenuBar" on wxFrame dialog).

3. Add next four menu item to "File" menu: "Load", "Town", "Outdoor", "Exit"

4. Add a panel to sizer slot

5. Generate C++ code

 

6. Isolate the basic data objects from global.h and Library.cpp and add them

7. Isolate void load_campaign() (Bl A Fileio.cpp) and bind it to "Load" menu.

Use fixed file path to avoid file load dialog.

 

I'll isolate 2D/3D graphic system and connect them to the panel view.

 

Tool palette

Next is the tool palette function of current 3D editor.

 

ToolPalette3D.jpg

 

From Bl A Editor.cpp

short overall_mode;

// 0 - 9 - different errain painting modes

// 10 - 29 - editing rectangle modes:

(0,0) T/O 0 "", "" neutral state, editing terrain/spaces with pencil

(1,0) T/O 1 "Paintbrush (large)", ""

(2,0) T/O 2 "Paintbrush (small)", ""

(3,0) T/O 3 "Spraycan (large)", ""

(4,0) T/O 4 "Spraycan (small)", ""

(5,0) T/O 20 "Set Height", "Select rectangle to set"

(6,0) T/O 11 "Fill rectangle (hollow)", "Select upper left corner"

(7,0) T/O 10 "Fill rectangle (solid)", "Select upper left corner"

 

(0,1) T/O large/small 3D Realistic mode toggle

(1,1) T/O floor - terrain - height toggle

(2,1) T/O Automatic hill toggle

(3,1) T/O 59 "Edit sign", "Select sign to edit"

(4,1) T/O 21 "Create room rectangle", "Select upper left corner"

(5,1) T/O 60 "Place 1st spawn point", ""

(6,1) O 22 "Create town entrance", "Select upper left corner"

(7,1) O 69 "Edit town entrance", ""

 

(0,2) T/O 19 "Place bounding walls", ""

(1,2) T/O 18 "Swap walls 1 <--> 2", "Select rectangle to set"

(2,2) T/O Change terrain randomly

(3,2) T 70 "Place Terrain Script", "Only in towns."

(4,2) T/O 2D/3D toggle

(5,2) T/O 16 "Create Special Encouter", "Select rectangle for encounter"

(6,2) T/O 49 "Erase Special Encouter", ""

(7,2) T/O 50 "Edit Special Encouter", ""

 

(0,3) T 40 "Select/edit placed object", "Select object to edit"

(1,3) T 41 "Delete an object", "Select object"

(2,3) T 57 "Place a Waypoint", "" Nav point

(3,3) T 58 "Delete Waypoint", "" Nav point

(4,3) T 30 "Place north entrance", "Select entrance location"

(5,3) T 31 "Place west entrance", "Select entrance location"

(6,3) T 32 "Place south entrance", "Select entrance location"

(7,3) T 33 "Place east entrance", "Select entrance location"

 

(0,4) T 61 "Make Spot Blocked", "Select location"

(1,4) T 62 "Place web", "Select location"

(2,4) T 63 "Place crate", "Select location"

(3,4) T 64 "Place barrel", "Select location"

(4,4) T 65 "Place fire barrier", "Select location"

(5,4) T 66 "Place force barrier", "Select location"

(6,4)

(7,4) T 67 "Clear space", "Select space to clear"

 

(0,5) T 68-0 "Place small blood stain", "Select stain location"

(1,5) T 68-1 "Place ave. blood stain", "Select stain location"

(2,5) T 68-2 "Place large blood stain", "Select stain location"

(3,5) T 68-3 "Place small slime pool", "Select slime location"

(4,5) T 68-4 "Place large slime pool", "Select slime location"

(5,5) T 68-5 "Place dried blood", "Select dried blood location"

(6,5) T 68-6 "Place bones", "Select bones location"

(7,5) T 68-7 "Place rocks", "Select rocks location"

Link to comment
Share on other sites

Quote:
Originally written by Notus:

1. Using wxGlade, make an application with a wxFrame
2. Add menubar to wxFrame (Widget tab - "Has MenuBar" on wxFrame dialog).
3. Add next four menu item to "File" menu: "Load", "Town", "Outdoor", "Exit"
4. Add a panel to sizer slot
5. Generate C++ code
I'll do this and load it into a CVS repository of its own (named wxBoAEditor). If I have more time, I'll start working on 6.

Quote:
Originally written by Kelandon:

If you can, incorporate the changes from Khoth's BetterEditor. They're small and simple but useful.
This shouldn't be too hard, but it will be a while.

EDIT:

Put a preliminary wxGlade File (app layout.wxg) in the Repository. Has the main frame and menu items.

EDIT:

Finished wxGlade file; code is not generated.
Link to comment
Share on other sites

Done putting the structures in global.h into new files. Will load them onto the CVS a little later.

 

EDIT:

Quote:
Sent wxGlade setting file, wxTest000.wxg, to CVS

Ummm, I already made one, and its basically the same as yours (no status bar). It has all the menu items from the old editor, though.
Link to comment
Share on other sites

Quote:
Originally written by Notus:
Anyway, we don't use the code generated by wxGlade as it is. I think it is a "customizable example maker". After we know how to code, editing code on the text editor is easier than setting parameters on wxGlade GUI. For example, we can add menu items faster on a text editor.
We should still use the generated code as a template for our own code, it should be pretty organized.

Coding using wxWidgets is very, very, very simple. Because there was no real IDE for so long, the makers of wxWidgets created code that did most of the work itself. For example, you create a wxFrame by using the new operator, but it deletes itself upon its closing or the application quitting.

EDIT:

Created a parser that does scenario data script parsing using Boost.Spirit. It compiles, but is untested. If it works, it will drastically speed up development.

It was loaded into the CVS repository under the file names: "avs_parser.hpp" and "avs_parser.cpp".

EDIT:

Forgot about a few undefined functions in the parser. I'll finish those now.

EDIT:

Hmmm, its going to take more time than I thought. I had to put = operators for that game_data.hpp classes and put some other stuff into avs_parser.hpp. Hopefully this was all the extraneous stuff I have to code.

EDIT:

Finished the parser. Its still inefficient, but several times more efficient and much cleaner than the original. I'll test it now, and when it works completely, I'll put more comments in.

EDIT:

Nope, doesn't work, but I know why. If I can't fix it soon, I'll load the original script parser.
Link to comment
Share on other sites

The data that fills the scen_data object in the Editor is held in the scripts "corescendata.txt" and "corescendata2.txt". My parser parses these scripts and loads the data, much more efficiently than the one in the old editor. It also must load a specific scenario's own scenario data script before editing the towns, outdoor sects, etc.

 

EDIT:

 

If you want to know what a parser is in general, then it is a utility that reads scripts, and checks them. Its just programming lingo for script checker (Alint is a parser).

 

EDIT:

 

Actually, a parser can read/check any type of grammar. They're usually made for scripting languages/programming languages.

Link to comment
Share on other sites

The first plan for the user command interface including Tool palette is almost finished. I'll concentrate implementation of the graphic system this week.

Because of the entrance examination of our University, I couldn't take so much time last week. (Japanese school starts on April.)

 

[Edit]

KernelKnowledge12

Please retrieve the previous build (build0026) of Win 3D editor from CVS, and cut out the data loader part. That version worked fine as the loader to the data object, but I gave up it by another problem I told. We can use it on our new editor. Revise it by your new template style. Show me a good example of template implementation wink

 

Retrieve procedure is,

1. In a new folder, execute "CVS Checkout...".

2. Select "Win3DBoAEditor/source" in Module tag.

3. Click Revision tag on the top of the TortoiseCVS dialog.

4. Check "Choose branch or tag"

5. Push "Update list.." button and connect CVS server to retrieve tags.

6. Now you get tag list on the pull-down menu, left of the push button.

7. Select "Build0026", the second one.

8. Push "OK" button at the bottom.

9. The connection to the CVS server retrieves the Build0026 version.

 

Maybe next parts are useful.

Bl A Fileio.cpp

do_load_campaign(), load_outdoor(), load_town()

 

CMemStream.h, CMemStream.cpp

 

global.h and Library.cpp

ReadDataFromStream(), WriteDataToStream() of each data object

Link to comment
Share on other sites

Quote:
Originally written by Notus:

Please retrieve the previous build (build0026) of Win 3D editor from CVS, and cut out the data loader part. That version worked fine as the loader to the data object, but I gave up it by another problem I told. We can use it on our new editor. Revise it by your new template style. Show me a good example of template implementation wink
I've looked at the save/load functions, and I have a few ideas. (I'll go ahead and do them, but I won't load it onto SourceForge until I get your approval. Actually I loaded some stuff before I read this, but this shouldn't be a problem.)

1) First, I'd like to change it to use fstream, and Spirit's file_iterator.
2) The save function is dependent upon the set_up_lights() function, which is an algorithm that works on terrains. I'd like to start a modularization of BoA-centric algorithms. I'll create two files, "algo_base.hpp" and "terrain_algo.hpp".
3) The save/load functions are dependent on global data, and so cannot be extended to any other use. I'd like to change their declarations to:

save_campaign( const char* __original, const char* __to );
load_campaign( const char* __from );

Concerning my parser:

Since my parser uses Spirit, which uses an excessive amount of template metaprogramming, it can be a strain on the compiler. To fix this I tried to put the actual functor definitions along with the parser's grammar definition in a .cpp file, so it won't compile every time the header is included. This, however, created linker errors that made no sense. Do you know of another way to solve this problem?
Link to comment
Share on other sites

Quote:
2) The save function is dependent upon the set_up_lights() function, which is an algorithm that works on terrains. I'd like to start a modularization of BoA-centric algorithms. I'll create two files, "algo_base.hpp" and "terrain_algo.hpp".
Yes, set_up_lights() etc. should be moved to the command handler that calls the loader for modularization.

Quote:
Since my parser uses Spirit, which uses an excessive amount of template metaprogramming, it can be a strain on the compiler. To fix this I tried to put the actual functor definitions along with the parser's grammar definition in a .cpp file, so it won't compile every time the header is included. This, however, created linker errors that made no sense. Do you know of another way to solve this problem?
Did you try clean build including pre-compiled header? Pre-compiled header and incremental link sometimes falls out of tune even in non-template C++ code. Delete pre-compiled header .pch and object files and execute recompile. If many compile errors appear after deleting pre-compiled header, compile switch is not set properly.
"The strain on the compiler" may also be caused by the same reason.

Tool and other palette design
Appearance of Tool and other palette
Most of the function of the original tool palette is divided into these palette.

ToolPalettePlan1.png

The explanation of palettes function. Can you imagine function of each button without next explanation?

ToolPaletteExp.png

Context menu
Context menu appears when user enters double click on the edit screen. Alternative way is Command (Apple)-click (Macintosh) or right mouse button click (Windows).
* means that the command is effective to the selected area.

Context menu for town edit screen
-- Place bounding walls *
-- Swap walls 1 <--> 2 *
-- Create Area description *
-- Edit Sign
-- Edit Terrain Script
-- Create Special Encounter *
-- Edit Special Encouter
-- Erase Special Encouter
-- Edit placed object
-- Delete object
-- Delete Waypoint
-- Set NY All *
-- Reset NY All *

Context menu for outdoor edit screen
-- Place bounding walls *
-- Swap walls 1 <--> 2 *
-- Create Area description *
-- Edit Sign
-- Create town entrance *
-- Edit Town Entrance
-- Create Special Encounter *
-- Edit Special Encouter
-- Erase Special Encouter

Check box on edit windows
New editor can open several edit window for towns and outdoor at the same time. Each edit window has next display setting checkbox.

-- 3D display toggles 2D/3D display
-- Realistic (3D only) switch display to realistic mode
-- Zoom out (2D only) display with small icon
-- Height (2D only) display height number on each square <-- when height tool is selected, set to this mode automatically
Link to comment
Share on other sites

Your designs look great smile !

 

As for my code, it might be awhile. I was able to write the parser quickly because a few storms closed the school systems for quite a while. I just finished a few metafunctions for the terrain classes (tiny_tr_type,ave_tr_type,big_tr_type), and I've commented a few of the files. I haven't loaded the metafunctions onto the CVS server yet, but I will soon.

Link to comment
Share on other sites

An error?

 

When I attempt to copy text outside of the BoA application and paste it into the "Intro Text" dialog boxes, I get nothing. I tried coping text from within the scenario and I had no problems. I attempted to copy from the outside again and I all got was the text I had copied from another dialog box. I tried this 3 more times before I gave up.

 

OS 10.2.8, Latest Version.

Link to comment
Share on other sites

This is not an error, just an example of how primitive the editor is. In the new editor, this will not be a problem, but chances are it won't be fixed in the old editor.

 

I am also curious as to how you managed to copy text within the application. I checked the code, and I couldn't find anything that would account for such a feature. Of course, I only looked in the Windows code.

Link to comment
Share on other sites

Quote:
Not in the Windows version. I guess Jeff wasn't as lazy when he created the Mac version of the editor.
To be fair for JV, he did nothing on copy-paste of text on dialogs in either Mac or Win Editor. It's the difference of basic OS support or history.
MacOS has defined copy-paste shortcut keys on its user interface guidline, and supports it on OS as default. But Windows did't specify key assignment, though it has API to support copy-paste.

Mac has two "clipboards", internal clipboard (within application) and system clipboard (between application). As the internal clipboard is supported by default, Mac application can copy-paste within the application. But to interact with the system clipboard, we should implement a transfer procedure between system and internal clipboard when the application becomes front or background.
Don't you have an experience when Photoshop becomes background, it asks "Do you want to convert large clipboard?"

Quote:
Funny -- I've never seen keyboard commands work when the menus are grayed out, but they do here.
It's the result of sweat of programmers. Synchronization of "Edit" menu and clipboard owes to coding.

To enable TRUE copy-paste on the dialogs on the current editor takes much time to implement, because it affects all dialogs and we should examine it. Please wait the new editor.
Link to comment
Share on other sites

I've started porting a rather long string of functions into the new editor, and I've found it neccessary to remake most of them. To do this, I've created a line class with three iterators (in line.hpp), and made a new direction system (in directional.hpp). The line class' tile_iterator will be used on the old_can_see, etc. functions, which I plan to split into four separate functions.

 

Notus, Isaac (any other developers who are working on this), please take a look at these files, and make sure you don't see anything wrong with them.

 

I believe I'll have these functions done by the end of the weekend:

 

look_block

move_block

old_can_see_to

old_can_see_in

old_can_travel_to

old_can_travel_in

set_up_lights

 

After this, I should be able to finish the file i/o functions pretty fast.

 

EDIT:

 

Nevermind about my direction system; I don't believe I was thinking clearly when I coded it. Also, I think I'll only split the old_can_see function into two different functions.

 

EDIT:

 

FYI, I only tested my tile iterator for forward iteration. It my not work with backward iteration, but I'll test it soon.

 

EDIT:

 

I was looking at the terrain classes (ave_tr_type, big_tr_type, tiny_tr_type) and I thought it would speed things up if instead of holding indexes to a specific floor or terrain, they held the actual pointers to the objects. This way instead of referencing the scen_data object every time a terrain was drawn, the program could just use the terrain object.

 

Notus, would this be a good idea, and if so, should we implement it now or later?

Link to comment
Share on other sites

Sorry, I should go back to my home town now. I'll return tomorrow.

 

town's limit

 

class scenario_data_type {

...

unsigned char num_towns;

...

// town data

unsigned char town_size[200]; // 0 - large, 1 - medium, 2 - small

unsigned char town_starts_hidden[200];

...

}

 

num_towns counts the number of towns actually implemented in .bas file.

The arrays, town_size[] and town_starts_hidden[], shows attribute of corresponding towns. If number of towns exceed 200, the towns which index is more than (and equal to) 200 cannot have these attributes. Thus, the maximum number of towns is 200.

Link to comment
Share on other sites

I just finished the algorithms neccessary for set_up_lights to function (sorry for the delay). It is loaded into the CVS, but I think I should look it over some. It isn't commented, so I apologize for any confusion. I'll work on the fileio tomorrow, and then write the old_can_travel functions.

 

Just saw the town limit part of your post Notus. I think I forgot that the editor writes those 2 arrays as full length no matter how many towns there are. The BoA application, then, must read it in this way. Thank you for clearing this up.

 

EDIT:

 

Finished with the save_campaign() function.

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.

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