[jsword-devel] New Developer
Aleksander Rozman - Andy
jsword-devel@crosswire.org
Sat, 20 Dec 2003 17:57:05 +0100
--=====================_19799710==_
Content-Type: text/plain; charset="us-ascii"; format=flowed
At 20.12.2003, you wrote:
>Aleksander Rozman - Andy wrote:
>
>>I never install on default possition. When I tried to select directory I
>>couldn't (for main bible directory), because file selection is enabled
>>and not directory. Also when I set directory nothing is found. So far I
>>have one bible KJV+.bbl in windows install directory (e-Sword)....
>>I also downloade RAW instalation files and copied contects of zip to
>>resources dir. but it doesn't work....
>
>Don't confuse us with e-Sword. I appreciate the names are confusing, but
>e-Sword has nothing to do with the SWORD project or JSword. JSword does
>not read e-Sword files, and to the best of my knowledge neither does C++ SWORD.
Oh Ok. I will try to download real Sword program....
>>>>- Status bar, text is resizing whole status bar. Status bar elements
>>>>are not the same size (borders)
>>>
>>>I'm not seeing this - I do get the status bar adjusting the space it
>>>gives to elements within itself, but then whole thing stays the same size.
>>Reallly? Try going to different items (which should print some text in
>>status) now this resizes everything...
>
>Not here. Tried on XP and 2K. What are you on?
XP on Java 1.4.1
>>>>Nifty things to be done:
>>>>- i18n
>>>
>>>Work started - many resources are read using Msg (resource classes in
>>>many packages)
>>>The idea is that you get to write in English first without needing to
>>>add lots of resource files or discovering that the key you are using
>>>no-longer exists in the resource file or the other way around.
>>>However Many gui elements don't use Msg and I've not actually created
>>>any translation files. It may look English only, but it isn't MsgBase
>>>allows resource files to override the english text.
>>It would be better if we created language files (plain text) for each
>>language , plugins will of course have their own language files (if
>>needed)... It's very unwise to put strings in classes. In old versions of
>>i18n it was practice to put all string in class files, but in newer
>>version, usually *properties files are created with String definitions,
>>and they are read when software needs it.
>>I have already done this, and I can tell you it's the best way. Strings
>>are cached, but not all of them.... (if strings are defined in classes,
>>they reside in memory for as long as class exists....
>
>I think Msg provides the best of both worlds. It allows the developer to
>hardcode strings for speed and simplicity, and then override them using a
>properties file later. MsgBase is worth a look it does use properties files.
I am sending you how I have done it before.... I have changed two classes
for now... I18nControl is file that accesses one file for language (just
one), this singelton instance, which means that is only initialized once,
and only one instance is present through running of whole program...
I am sending 4 files. JSword_EN.properties (put into ./resource),
I18nControl.java (into common/org/crosswire/common/resource) and two
samples (into jsword/org/crosswire/jsword/view/swing/desktop)
AboutPane.java, BlurAction.java
>>>>- adding of Skinlf support (SkinLF is library that alows adding of
>>>>several types of themes, L&F
>>>
>>>Should be supported already. Add the skinlf to your classpath and type
>>>the L&F class name into the options dialog.
> >
>>This won't work. SkinLF needs one parameter (File with Look and feel) and
>>it must be enabled (quite different than normal L&F), which means that we
>>need special configuration window... I can do this if you want?
>
>Is this parameter a passed in the ctor or another way?
Here is the code to activate SkinLF.
com.l2fprod.gui.plaf.skin.SkinLookAndFeel.setSkin(com.l2fprod.gui.plaf.skin.SkinLookAndFeel.loadThemePack("./aquathemepack.zip"));
com.l2fprod.gui.plaf.skin.SkinLookAndFeel.enable();
>>>>- Help (this could be done with JavaHelp)
>>>
>>>Or even a Book! I think the core job of displaying and searching Bible
>>>data is very similar to JavaHelp's job.
>>Yes it is. We could probably use JavaHelp to display bible (with some
>>modifications)
>
>I think HTML is a much more broadly understood standard, and it allows us
>to output to the web rather than a Swing JEditorPane too.
To Web? I am sorry I didn't understand this... Will you use JavaHelp or not?
>Joe.
>
>
>_______________________________________________
>jsword-devel mailing list
>jsword-devel@crosswire.org
>http://www.crosswire.org/mailman/listinfo/jsword-devel
**************************************************************************
* Aleksander Rozman - Andy * Fandoms: E2:EA, SAABer, Trekkie, Earthie *
* andy@kksonline.com * Sentinel, BH 90210, True's Trooper, *
* andy@atechnet.dhs.org * Heller's Angel, Questie, Legacy, PO5, *
* Maribor, Slovenia (Europe) * Profiler, Buffy (Slayerete), Pretender *
* ICQ-UIC: 4911125 *********************************************
* PGP key available * http://www.atechnet.dhs.org/~andy/ *
**************************************************************************
--=====================_19799710==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="I18nControl.java"
package org.crosswire.common.resource;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.MissingResourceException;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
import java.util.*;
import java.text.DateFormat;
public class I18nControl
{
/**
* Resource bundle identificator
*/
ResourceBundle res;
static private I18nControl m_i18n = null; // This is handle to unique
// singelton instance
// Constructor: OmniI18nControl
/**
*
* This is OmniI18nControl constructor; Since classes use Singleton Pattern,
* constructor is protected and can be accessed only with getInstance()
* method.<br><br>
*
*/
private I18nControl()
{
setLanguage("EN");
}
// Method: getInstance
// Author: Andy
/**
*
* This method returns reference to OmniI18nControl object created, or if no
* object was created yet, it creates one.<br><br>
*
* @return Reference to OmniI18nControl object
*
*/
static public I18nControl getInstance()
{
if (m_i18n == null)
m_i18n = new I18nControl();
return m_i18n;
}
// Method: deleteInstance
/**
*
* This method sets handle to OmniI18NControl to null and deletes the instance. <br><br>
*
*/
public void deleteInstance()
{
m_i18n=null;
}
// Method: setLanguage (String language)
/**
*
* This is helper method for setting language.<br><br>
*
* @param language language which we want to use
*/
public void setLanguage(String language)
{
Locale l = new Locale(language);
setLanguage(l);
}
// Method: setLanguage (String language, String country)
/**
*
* This is helper method for setting language.<br><br>
*
* @param language language which we want to use
* @param country country that uses this language
*/
public void setLanguage(String language, String country)
{
Locale l = new Locale(language, country);
setLanguage(l);
}
// Method: setLanguage (Locale)
/**
*
* This method sets language for control instance. If none is found, english is defaulted.
* if none is found, application will exit.<br><br>
*
* @param lcl locale that will choose which language will be set
*/
public void setLanguage(Locale lcl)
{
try
{
res = ResourceBundle.getBundle("../resource/JSword", lcl);
}
catch (MissingResourceException mre)
{
try
{
res = ResourceBundle.getBundle("../resource/JSword", new Locale("EN"));
}
catch(Exception ex)
{
System.out.println("Exception on reading resource file. Exiting application.");
System.exit(2);
}
}
}
// Method: hmmlize
/**
*
* Converts text from bundle into HTML. This must be used if we have control, which has
* formated text in HTML or is multilined (some of basic java swing components don't
* support \n).
*
* @param input input text we wish to HTMLize
* @return HTMLized text
*
*/
private String htmlize(String input)
{
StringBuffer buffer = new StringBuffer("<HTML>");
input = input.replaceAll("\n", "<BR>");
input = input.replaceAll("&", "&");
buffer.append(input);
buffer.append("</HTML>");
return buffer.toString();
}
// Method: getMessageHTML(String)
/**
*
* Helper method to get HTMLized message from Bundle
*
* @param msg non-htmlized (or partitialy HTMLized tekst)
* @return fully HTMLized message
*
*/
public String getMessageHTML(String msg)
{
String mm = this.getMessage(msg);
return htmlize(mm);
}
// Method: getString
/**
*
* This helper method calls getMessage(String) and returns message that is
* associated with inserted code. It is implemented mainly, because some
* programmers are used that resource nsg is returned with this command.
*
* @param msg id of message we want
* @return value for code, or same code back
*/
public String getString(String msg)
{
return this.getMessage(msg);
}
// Method: returnSameValue (String)
/**
*
* Returns same value as it was sent to catalog in case that catalog entry was not
* found. This message has inserted spaces so that is easier readable.
*
* @param msg id of message we want
* @return same code back (formated)
*/
private String returnSameValue(String msg)
{
// If we return same msg back, without beeing resolved, we put spaces before %, so
// that it is much easier readable.
if (msg.indexOf("%")==-1)
return msg;
StringBuffer out=new StringBuffer();
int idx;
while ((idx=msg.indexOf("%"))!=-1)
{
out.append(msg.substring(0, idx));
out.append("|%");
msg = msg.substring(idx+1);
}
out.append(msg);
return out.toString();
}
// Method: resolveMnemonic(String)
/**
* This method extracts mnemonics from message string. Each such string can
* contain several & characters, even double &. Last & in String is mnemonic
* while other are discarded. Double && is resolved to single & in text. We
* return array of Object. First entry contains mnemonic if this is null, we
* didn't find any mnemonic. Second entry is text without mnemonic and changed
* && substrings. If whole object is returned as null, then String didn't
* contain any & signs.
*
* @param msg message from message catalog
* @return array of Object, containg max. two elements, null can also be returned
*
*/
private Object[] resolveMnemonics(String msg)
{
if (msg.indexOf("&")==-1)
return null;
Object back[] = new Object[2];
int msg_length = msg.length();
int code[] = new int[msg_length];
boolean foundDouble=false;
boolean foundMnemonic=false;
for (int i=0;i<msg_length;i++)
{
if (msg.charAt(i)=='&')
{
// we found mnemonic sign
code[i]=1; // 1 if & sign
if (i!=0)
{
// check for double &
if (code[i-1]==1) // double & are marked 2
{
code[i-1]=2;
code[i]=2;
foundDouble=true;
}
}
}
else
code[i]=0;
}
// now we find real menmonic
for (int i=msg_length-1; i>-1; i--)
{
if (code[i]==1)
{
code[i]=3;
if (i==msg_length-1) // if & is last char we ignore it
{
code[i]=1;
}
else
{
foundMnemonic=true;
break;
}
}
}
StringBuffer returnStr = new StringBuffer();
int lastChange=0;
for (int i=0; i<msg_length;i++)
{
if (code[i]==1) // all & (tagged 1) are removed
{
returnStr.append(msg.substring(lastChange, i));
lastChange=i+1;
}
else if (code[i]==2) // all && are replaced with one &
{
returnStr.append(msg.substring(lastChange, i));
returnStr.append("&");
lastChange=i+2; // was 2
i=i+1;
}
else if (code[i]==3) // this is mnemonic
{
back[0]=new Character(msg.charAt(i+1));
returnStr.append(msg.substring(lastChange, i));
lastChange=i+1;
}
}
returnStr.append(msg.substring(lastChange));
back[1] = returnStr.toString();
if (!foundMnemonic)
back[0]=null;
return back;
}
// Method: getMnemonic
/**
* Returns mnemonic of String that is stored in bundle as msg_id. If mnemonic is
* not found 0 is returned. Calls private method resolveMnemonics.
*
* @see resolveMnemonic
* @param msg_id id of message in bundle
* @return int representation of char that is mnemonic, 0 if none found
*/
public char getMnemonic(String msg_id)
{
try
{
Object[] back = resolveMnemonics(getMessageFromCatalog(msg_id));
if ((back==null) || (back[0]==null))
return 0;
return ((Character)back[0]).charValue();
}
catch (Exception e)
{
return 0;
}
}
// Method: getMessageWithoutMnemonic
/**
* Returns String that is stored in bundle as msg_id. It also removes
* mnemonic signs and removed double &. Calls private method resolveMnemonics.
*
* @see resolveMnemonic
* @param msg_id id of message in bundle
* @return String message from catalog, woithout mnemonic and double &
*/
public String getMessageWithoutMnemonic(String msg_id)
{
try
{
String ret = getMessageFromCatalog(msg_id);
Object[] back = resolveMnemonics(ret);
if (back==null)
return ret;
else
return (String)back[1];
}
catch(Exception ex)
{
return returnSameValue(msg_id);
}
}
// Method: getMessageFromCatalog
/**
* Looks into bundle and returns correct message. This method is syncronized, so only one
* message at the time can be returned.
*
* @param msg id of message in bundle
* @return String message from catalog.
*/
private synchronized String getMessageFromCatalog(String msg)
{
try
{
if (msg==null)
return "null";
String ret = res.getString(msg);
if (ret==null)
return returnSameValue(msg);
else
return ret;
}
catch(Exception ex)
{
return returnSameValue(msg);
}
}
// Method: getMessage (String)
/**
*
* Helper method to get message from Bundle.
*
* @param msg id of message we want
* @return value for code, or same code back
*/
public String getMessage(String msg)
{
return getMessageFromCatalog(msg);
}
public static void main(String args[])
{
I18nControl oc = I18nControl.getInstance();
// System.out.println(oc.getMessage(12, 1));
}
}
--=====================_19799710==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="JSword_EN.properties"
# [About]
ABOUT=&About
ABOUT_SHORTDESC=The more information about
ABOUT_LONGDESC=Investigate tasks, errors and logs
# [Blur]
BLUR_BY=Blur by
VERSE=verse
BLUR_PASAGE_BY=Blur passage by
BLUR_THE_CURRENT_PASSAGE_BY=Blur the current passage by
# [Main]
VERSION=Version
RUNNING_TASKS=Running Tasks
ERRORS=Errors
SYSTEM_PROPERTIES=System Properties
DEBUG=Debug
OK=&Ok
--=====================_19799710==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="AboutPane.java"
package org.crosswire.jsword.view.swing.desktop;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.URL;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import org.crosswire.common.progress.swing.JobsViewPane;
import org.crosswire.common.resource.I18nControl;
import org.crosswire.common.swing.ExceptionShelf;
import org.crosswire.common.swing.MapTableModel;
import org.crosswire.jsword.util.Project;
/**
* AboutPane is a window that contains various advanced user tools in
* one place.
*
* <p><table border='1' cellPadding='3' cellSpacing='0'>
* <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
*
* Distribution Licence:<br />
* JSword is free software; you can redistribute it
* and/or modify it under the terms of the GNU General Public License,
* version 2 as published by the Free Software Foundation.<br />
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.<br />
* The License is available on the internet
* <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
* Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA<br />
* The copyright to this program is held by it's authors.
* </font></td></tr></table>
* @see gnu.gpl.Licence
* @author Joe Walker [joe at eireneh dot com]
* @version $Id: AboutPane.java,v 1.6 2003/11/30 19:58:26 joe Exp $
*/
public class AboutPane
{
private I18nControl ic = I18nControl.getInstance();
/**
* Basic constructor
*/
public AboutPane(Desktop desktop)
{
// Object creation that must be postponed
pnl_debug = new DebugPane(desktop);
jbInit();
}
/**
* Build the GUI components
*/
private void jbInit()
{
URL url = getClass().getResource("/images/splash.png");
if (url != null)
{
icon = new ImageIcon(url);
}
lbl_picture.setIcon(icon);
lbl_picture.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
lbl_picture.setHorizontalAlignment(SwingConstants.CENTER);
lbl_picture.setVerticalAlignment(SwingConstants.CENTER);
lbl_info.setFont(new Font("SansSerif", 1, 14));
lbl_info.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
lbl_info.setOpaque(true);
lbl_info.setHorizontalAlignment(SwingConstants.RIGHT);
lbl_info.setText(ic.getMessage("VERSION")+" "+Project.instance().getVersion());
pnl_splash.setLayout(new BorderLayout(5, 0));
pnl_splash.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
pnl_splash.add(lbl_picture, BorderLayout.CENTER);
pnl_splash.add(lbl_info, BorderLayout.SOUTH);
pnl_hshelf.setLayout(new BorderLayout());
pnl_hshelf.add(pnl_shelf, BorderLayout.NORTH);
pnl_hshelf.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
tbl_props.setModel(mdl_props);
scr_props.setPreferredSize(new Dimension(500, 300));
scr_props.getViewport().add(tbl_props);
pnl_props.setLayout(new BorderLayout());
pnl_props.add(scr_props, BorderLayout.CENTER);
pnl_props.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
tab_main.add(pnl_splash, Project.instance().getName());
tab_main.add(pnl_jobs, ic.getMessage("RUNNING_TASKS"));
tab_main.add(pnl_hshelf, ic.getMessage("ERRORS"));
tab_main.add(pnl_props, ic.getMessage("SYSTEM_PROPERTIES"));
//tab_main.add(pnl_logs, "Logs");
tab_main.add(pnl_debug, ic.getMessage("DEBUG"));
btn_ok.setText(ic.getMessage("OK"));
btn_ok.setMnemonic(ic.getMnemonic("OK"));
btn_ok.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ev)
{
close();
}
});
pnl_buttons.add(btn_ok);
pnl_main.setLayout(new BorderLayout(5, 5));
pnl_main.add(pnl_buttons, BorderLayout.SOUTH);
pnl_main.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
pnl_main.add(tab_main, BorderLayout.CENTER);
}
/**
* Close this dialog
*/
protected void close()
{
if (dlg_main != null)
{
dlg_main.dispose();
dlg_main = null;
}
}
/**
* A method to be exposed by our children
* @param parent The component to which to attach the new dialog
*/
public void showInDialog(Component parent)
{
dlg_main = new JDialog(JOptionPane.getFrameForComponent(parent));
dlg_main.getContentPane().add(pnl_main);
dlg_main.setTitle(ic.getMessageWithoutMnemonic("ABOUT")+" "+Project.instance().getName());
dlg_main.setModal(true);
dlg_main.addWindowListener(new WindowAdapter()
{
public void windowClosed(WindowEvent ev)
{
close();
}
});
dlg_main.pack();
dlg_main.setLocationRelativeTo(parent);
dlg_main.setVisible(true);
}
/**
* Is the debug tab visible?
*/
public static boolean isDebugging()
{
return debugging;
}
/**
* Set the visibility of the debug tab?
*/
public static void setDebugging(boolean debugging)
{
AboutPane.debugging = debugging;
}
private static boolean debugging = false;
private Icon icon;
private JLabel lbl_picture = new JLabel();
private JLabel lbl_info = new JLabel();
private JPanel pnl_splash = new JPanel();
private MapTableModel mdl_props = new MapTableModel(System.getProperties());
private JScrollPane scr_props = new JScrollPane();
private JPanel pnl_props = new JPanel();
private JTable tbl_props = new JTable();
private ExceptionShelf pnl_shelf = new ExceptionShelf();
private JPanel pnl_hshelf = new JPanel();
private JobsViewPane pnl_jobs = new JobsViewPane();
private JTabbedPane tab_main = new JTabbedPane();
//private JPanel pnl_logs = new JPanel();
private DebugPane pnl_debug = null;
private JDialog dlg_main;
private JPanel pnl_main = new JPanel();
private JPanel pnl_buttons = new JPanel();
private JButton btn_ok = new JButton();
/**
* Create an 'open' Action
*/
public static Action createOpenAction(Desktop desktop)
{
return new OpenAction(desktop);
}
/**
* An Action to open a new one of these
*/
public static class OpenAction extends DesktopAbstractAction
{
/**
* Simple ctor
*/
public OpenAction(Desktop desktop)
{
super(desktop,
I18nControl.getInstance().getMessageWithoutMnemonic("ABOUT")+" ...",
"toolbarButtonGraphics/general/About16.gif",
"toolbarButtonGraphics/general/About24.gif",
I18nControl.getInstance().getMessage("ABOUT_SHORTDESC")+" "+Project.instance().getName(), I18nControl.getInstance().getMessage("ABOUT_LONGDESC"),
I18nControl.getInstance().getMnemonic("ABOUT"), null);
atp = new AboutPane(getDesktop());
}
/* (non-Javadoc)
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent ev)
{
atp.showInDialog(getDesktop().getJFrame());
}
private AboutPane atp = null;
}
}
--=====================_19799710==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="BlurAction.java"
package org.crosswire.jsword.view.swing.desktop;
import java.awt.event.ActionEvent;
import org.crosswire.jsword.passage.Passage;
import org.crosswire.common.resource.I18nControl;
import org.crosswire.jsword.view.swing.book.BibleViewPane;
/**
* Blur the current passage action.
*
* <p><table border='1' cellPadding='3' cellSpacing='0'>
* <tr><td bgColor='white' class='TableRowColor'><font size='-7'>
*
* Distribution Licence:<br />
* JSword is free software; you can redistribute it
* and/or modify it under the terms of the GNU General Public License,
* version 2 as published by the Free Software Foundation.<br />
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.<br />
* The License is available on the internet
* <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, or by writing to:
* Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA<br />
* The copyright to this program is held by it's authors.
* </font></td></tr></table>
* @see gnu.gpl.Licence
* @author Joe Walker [joe at eireneh dot com]
* @version $Id: BlurAction.java,v 1.3 2003/08/30 22:14:08 joe Exp $
*/
public class BlurAction extends DesktopAbstractAction
{
I18nControl ic;
/**
* Ctor
*/
public BlurAction(Desktop tools, int amount, int restrict)
{
super(tools,
I18nControl.getInstance().getMessage("BLUR_BY")+" "+amount+" "+I18nControl.getInstance().getMessage("VERSE"),
null,
null,
I18nControl.getInstance().getMessage("BLUR_PASAGE_BY")+" "+amount+" "+I18nControl.getInstance().getMessage("VERSE"), I18nControl.getInstance().getMessage("BLUR_THE_CURRENT_PASSAGE_BY")+" "+amount+" "+I18nControl.getInstance().getMessage("VERSE")+".",
'0'+(char) amount, null);
this.amount = amount;
this.restrict = restrict;
}
/* (non-Javadoc)
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent ev)
{
BibleViewPane view = getDesktop().getSelectedBibleViewPane();
if (view != null)
{
Passage ref = view.getPassage();
ref.blur(amount, restrict);
view.setPassage(ref);
}
}
private int amount;
private int restrict;
}
--=====================_19799710==_--