text:
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.jab.docsearch.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.TitledBorder;

import org.apache.log4j.Logger;
import org.jab.docsearch.DocSearch;
import org.jab.docsearch.FileEnvironment;
import org.jab.docsearch.utils.DocTypeHandler;
import org.jab.docsearch.utils.I18n;
import org.jab.docsearch.utils.Messages;

/**
 * Class DsProperties
 *
 * @version $Id: DsProperties.java 172 2012-09-14 15:24:32Z henschel $
 */
public final class DsProperties extends JDialog implements ActionListener {
    /**
	 * Serial
	 */
	private static final long serialVersionUID = -5423671391062172275L;

	/**
     * Logging
     */
    private final static Logger logger = Logger.getLogger(DsProperties.class);

	/**
     * FileEnvironment
     */
    private final static FileEnvironment fEnv = FileEnvironment.getInstance();
    private final DocSearch monitor;
    private final int numPanels = 2;
    public static final String CANCEL = Messages.getString("DocSearch.btnCancel");
    public static final String OK = Messages.getString("DocSearch.ok");
    private static final String APPLY = Messages.getString("DocSearch.btnApply");
    private static final String BROWSE = Messages.getString("DocSearch.btnBrowse");
    private static final String SELECT = Messages.getString("DocSearch.btnSelect");
    private static final String PROVIDE_IDX_DIR = Messages.getString("DocSearch.provIdxDir");
    private static final String ADD = Messages.getString("DocSearch.btnAdd");
    private static final String REMOVE = Messages.getString("DocSearch.lblRemove");
    private static final String NEW_HANDLER = Messages.getString("DocSearch.newHandler");
    private static final String EDIT_HANDLER = Messages.getString("DocSearch.editHandler");
    private static final String EDIT = Messages.getString("DocSearch.btnEdit");
    private static final String DS_DIR = Messages.getString("DocSearch.dsIdxDir");
    private static final String DS_DIR_TAB = Messages.getString("DocSearch.lblIdxDir");
    private static final String DS_DIR_EXP = Messages.getString("DocSearch.dsIdxDirExp");
    private static final String COPY_DIR_FILES = Messages.getString("DocSearch.copyDirFiles");
    private static final String SELECT_DS_DIR = Messages.getString("DocSearch.selectDsIdxDir");
    private static final String TEMP_DIR = Messages.getString("DocSearch.tempDir");
    private static final String TEMP_DIR_EXP = Messages.getString("DocSearch.tempDirExp");
    private static final String SELECT_TEMP_DIR = Messages.getString("DocSearch.selectTempDir");
    private static final String SELECT_WORKING_DIR = Messages.getString("DocSearch.selectWorkingDir");
    private static final String WORKING_DIR_LABEL = Messages.getString("DocSearch.workingDirLbl");
    private static final String WORKING_DIR_EXP = Messages.getString("DocSearch.workingDirExp");
    private static final String WORKING_DIR_TITLE = Messages.getString("DocSearch.workingDirTitle");
    private static final String LOAD_WEB_PAGES_EXTERNALLY = Messages.getString("DocSearch.loadExternal");
    // email config
    private final JPanel completeEmailPanel = new JPanel();
    private final JPanel emailPanel = new JPanel();
    private final String EMAIL_ADDRESS = Messages.getString("DocSearch.emailAddress");
    private final String EMAIL_ADDRESSES = Messages.getString("DocSearch.emailAddresses");
    private final String EMAIL_SETTINGS = Messages.getString("DocSearch.emailSettings");
    private final String SEND_EMAIL_NOTICE_NOTE = Messages.getString("DocSearch.sendEmail");
    private final String SEND_EMAIL_NOTICE = Messages.getString("DocSearch.sendMail");
    private final String GATEWAY_USER = Messages.getString("DocSearch.gateWayUser");
    private final String NOTIFICATIONS = Messages.getString("DocSearch.notifications");
    private final String EMAIL_GATEWAY = Messages.getString("DocSearch.emailGateway");
    private final String GATEWAY_PWD = Messages.getString("DocSearch.gatewayPwd");
    private final String REMOVE_EMAIL = Messages.getString("DocSearch.removeEmail");
    private final String EDIT_EMAIL = Messages.getString("DocSearch.editEmail");
    private final String ADD_EMAIL = Messages.getString("DocSearch.addEmail");
    private final String EMAIL_FORMAT = Messages.getString("DocSearch.emailFormat");
    public String TEXT_FORMAT = Messages.getString("DocSearch.textFormat");
    public String HTML_FORMAT = Messages.getString("DocSearch.htmlFormat");
    private final String MAX_FILE_SIZE = Messages.getString("DocSearch.maxFsToIdx");
    //
    private final JLabel maxFiSizeLbl = new JLabel(MAX_FILE_SIZE);
    private final JTextField maxSizeField = new JTextField(10);
    private final JPanel maxFileSizePanel = new JPanel();
    //
    private final String MAX_HITS_LABEL = Messages.getString("DocSearch.maxHitsLbl");
    //private final String MAX_HITS_TITLE = Messages.getString("DocSearch.maxHitsTit");
    private final JLabel maxHitLbl = new JLabel(MAX_HITS_LABEL);
    private final JTextField maxField = new JTextField(5);
    private final JPanel maxPanel = new JPanel();
    private final JPanel maxAllPanel = new JPanel();
    //
    private final String[] emailAddresses = { "", "" };
    private final JList emailList = new JList(emailAddresses);
    private final JScrollPane emailPane = new JScrollPane(emailList);
    private final JPanel emailButtonsPanel = new JPanel();
    private final JButton editButton = new JButton(EDIT);
    private final JButton addButton = new JButton(ADD);
    private final JButton removeButton = new JButton(REMOVE);
    //
    private final JPanel gatewayPanel = new JPanel();
    private final JPanel noticePanel = new JPanel();
    private final JCheckBox sendEmailBx = new JCheckBox(SEND_EMAIL_NOTICE);
    private final JLabel sendEmailLbl = new JLabel(SEND_EMAIL_NOTICE_NOTE);
    //
    private final ButtonGroup bg = new ButtonGroup();
    private final JRadioButton textRB = new JRadioButton(TEXT_FORMAT);
    private final JRadioButton htmlRB = new JRadioButton(HTML_FORMAT);
    //
    private final JPanel gatewyp = new JPanel();
    private final JLabel gateWayLbl = new JLabel(EMAIL_GATEWAY);
    private final JTextField gateWayField = new JTextField(12);
    private final JPanel gatewayUserPanel = new JPanel();
    private final JLabel gatewayUserLbl = new JLabel(GATEWAY_USER);
    private final JTextField gatewayUserField = new JTextField(12);
    private final JPanel gatewayPwdPanel = new JPanel();
    private final JLabel gatewayPwdLbl = new JLabel(GATEWAY_PWD);
    private final JPasswordField gatewayPwdField = new JPasswordField(12);
    //
    private final String[] handlerItems = { "", "" };
    private final JList handlerList = new JList(handlerItems);
    //
    private final JPanel workingDirPanel = new JPanel();
    private final JPanel workingPanel = new JPanel();
    private final JLabel workingDirLbl = new JLabel(WORKING_DIR_LABEL);
    private final JLabel workingDirExpLbl = new JLabel(WORKING_DIR_EXP);
    private final JTextField workingDirField = new JTextField(12);
    private final JButton workingDirButton = new JButton(SELECT_WORKING_DIR);
    //
    private final JPanel tempDirPanel = new JPanel();
    private final JPanel tempFoldPanel = new JPanel();
    private final JLabel tempDirExpLbl = new JLabel(TEMP_DIR_EXP);
    private final JLabel tempDirLbl = new JLabel(TEMP_DIR);
    private final JTextField tempDirField = new JTextField(12);
    private final JButton tempDirButton = new JButton(SELECT_TEMP_DIR);
    //
    private final JLabel defaultHndlrLbl = new JLabel(Messages.getString("DocSearch.lblDfltHndlr"));
    private final JTextField defaultHndlrField = new JTextField(12);
    private final JButton browseButton = new JButton(BROWSE);
    //
    private final JPanel dsDirPanel = new JPanel();
    private final JLabel dsDirLabel = new JLabel(DS_DIR_EXP);
    private final JLabel dsDirFieldLabel = new JLabel(DS_DIR);
    private final JButton dsSelDirButton = new JButton(SELECT_DS_DIR);
    private final JCheckBox copyDirFiles = new JCheckBox(COPY_DIR_FILES);
    private final JTextField dsDirField = new JTextField(12);
    //
    private final JCheckBox loadExternal = new JCheckBox(LOAD_WEB_PAGES_EXTERNALLY);
    //
    private final JButton okButton = new JButton(APPLY);
    private final JButton cancelButton = new JButton(CANCEL);
    //
    private final JButton addEmailButton = new JButton(ADD_EMAIL);
    private final JButton removeEmailButton = new JButton(REMOVE_EMAIL);
    private final JButton editEmailButton = new JButton(EDIT_EMAIL);
    //
    private final JPanel allDirsPanel = new JPanel();
    //
    private final JPanel bp = new JPanel();
    private final JPanel leftSideListPanel = new JPanel();
    private final JScrollPane listPane = new JScrollPane(handlerList);
    private final JPanel rightButPanel = new JPanel();
    private final JPanel rbp = new JPanel();
    private final JPanel[] panels;
    private final JTabbedPane tp = new JTabbedPane();
    //
    private boolean confirmed = false;
    private int returnInt = -1;
    //
    private final JPanel uiPanel = new JPanel();
    private final String[] uiList = { "" };
    private final JComboBox uiChoice = new JComboBox(uiList);
    private final JLabel uiLabel = new JLabel(Messages.getString("DocSearch.uiChoice"));

    public DsProperties(DocSearch monitor, String title, boolean modal) {
        super(monitor, title, modal);
        this.monitor = monitor;
        listPane.setPreferredSize(new Dimension(350, 200));
        // set up the buttons
        okButton.addActionListener(this);
        cancelButton.addActionListener(this);
        browseButton.addActionListener(this);
        removeButton.addActionListener(this);
        editButton.addActionListener(this);
        addButton.addActionListener(this);
        sendEmailBx.addActionListener(new CbListener());
        removeEmailButton.addActionListener(this);
        editEmailButton.addActionListener(this);
        addEmailButton.addActionListener(this);
        //
        dsSelDirButton.addActionListener(this);
        tempDirButton.addActionListener(this);
        workingDirButton.addActionListener(this);
        //
        workingDirPanel.add(workingDirLbl);
        workingDirPanel.add(workingDirField);
        workingDirPanel.add(workingDirButton);
        //
        workingPanel.setLayout(new BorderLayout());
        workingPanel.setBorder(new TitledBorder(WORKING_DIR_TITLE));
        workingPanel.add(workingDirExpLbl, BorderLayout.NORTH);
        workingPanel.add(workingDirPanel, BorderLayout.CENTER);
        //
        maxPanel.add(maxHitLbl);
        maxPanel.add(maxField);
        //
        maxAllPanel.setLayout(new BorderLayout());
        // maxAllPanel.setBorder(new TitledBorder(MAX_HITS_TITLE));
        maxAllPanel.add(maxPanel, BorderLayout.CENTER);
        //
        tempFoldPanel.add(tempDirLbl);
        tempFoldPanel.add(tempDirField);
        tempFoldPanel.add(tempDirButton);
        //
        tempDirPanel.setLayout(new BorderLayout());
        tempDirPanel.setBorder(new TitledBorder(TEMP_DIR));
        tempDirPanel.add(tempDirExpLbl, BorderLayout.NORTH);
        tempDirPanel.add(tempFoldPanel, BorderLayout.CENTER);
        //
        JPanel uiP = new JPanel();
        uiP.add(uiLabel);
        uiP.add(uiChoice);
        //
        maxFileSizePanel.add(maxFiSizeLbl);
        maxFileSizePanel.add(maxSizeField);
        JPanel mfsW = new JPanel();
        mfsW.add(maxFileSizePanel);
        //
        JPanel comMaxP = new JPanel();
        comMaxP.setLayout(new BorderLayout());
        comMaxP.add(mfsW, BorderLayout.NORTH);
        comMaxP.add(maxAllPanel, BorderLayout.CENTER);
        JPanel cmpW = new JPanel();
        cmpW.add(comMaxP);
        //
        uiPanel.setLayout(new BorderLayout());
        uiPanel.add(uiP, BorderLayout.NORTH);
        uiPanel.add(cmpW, BorderLayout.CENTER);
        uiPanel.add(loadExternal, BorderLayout.SOUTH);
        JPanel uiWrap = new JPanel();
        uiWrap.add(uiPanel);
        //
        bg.add(textRB);
        bg.add(htmlRB);
        //
        leftSideListPanel.add(listPane);
        //
        bp.add(okButton);
        bp.add(cancelButton);
        //
        JPanel dirFieldPanel = new JPanel();
        dirFieldPanel.add(dsDirFieldLabel);
        dirFieldPanel.add(dsDirField);
        dirFieldPanel.add(dsSelDirButton);
        //
        dsDirPanel.setLayout(new BorderLayout());
        dsDirPanel.setBorder(new TitledBorder(DS_DIR));
        dsDirPanel.add(dsDirLabel, BorderLayout.NORTH);
        dsDirPanel.add(dirFieldPanel, BorderLayout.CENTER);
        dsDirPanel.add(copyDirFiles, BorderLayout.SOUTH);
        //
        allDirsPanel.setLayout(new BorderLayout());
        allDirsPanel.add(tempDirPanel, BorderLayout.NORTH);
        allDirsPanel.add(dsDirPanel, BorderLayout.CENTER);
        allDirsPanel.add(workingPanel, BorderLayout.SOUTH);
        //
        JPanel dp = new JPanel();
        dp.add(allDirsPanel);
        //
        rightButPanel.setLayout(new BorderLayout());
        rightButPanel.add(addButton, BorderLayout.NORTH);
        rightButPanel.add(removeButton, BorderLayout.CENTER);
        rightButPanel.add(editButton, BorderLayout.SOUTH);
        rbp.add(rightButPanel);
        // load up the GUI
        //
        okButton.setMnemonic(KeyEvent.VK_A);
        okButton.setToolTipText(APPLY);
        //
        //
        cancelButton.setMnemonic(KeyEvent.VK_C);
        cancelButton.setToolTipText(CANCEL);
        //
        browseButton.setMnemonic(KeyEvent.VK_B);
        browseButton.setToolTipText(BROWSE);
        //
        JPanel hndlerPanel = new JPanel();
        JPanel lowerHP = new JPanel();
        JPanel upperHP = new JPanel();
        upperHP.setLayout(new BorderLayout());
        upperHP.setBorder(new TitledBorder(Messages.getString("DocSearch.hndlrTitle")));
        upperHP.add(leftSideListPanel, BorderLayout.WEST);
        upperHP.add(rbp, BorderLayout.EAST);
        lowerHP.add(defaultHndlrLbl);
        lowerHP.add(defaultHndlrField);
        lowerHP.add(browseButton);
        //
        hndlerPanel.setLayout(new BorderLayout());
        hndlerPanel.add(upperHP, BorderLayout.CENTER);
        hndlerPanel.add(lowerHP, BorderLayout.SOUTH);
        //
        //
        emailButtonsPanel.setLayout(new BorderLayout());
        emailButtonsPanel.add(addEmailButton, BorderLayout.NORTH);
        emailButtonsPanel.add(removeEmailButton, BorderLayout.CENTER);
        emailButtonsPanel.add(editEmailButton, BorderLayout.SOUTH);
        JPanel emailCPpanel = new JPanel();
        emailCPpanel.add(emailButtonsPanel);
        //
        gatewayPwdPanel.add(gatewayPwdLbl);
        gatewayPwdPanel.add(gatewayPwdField);
        //
        gatewyp.add(gateWayLbl);
        gatewyp.add(gateWayField);
        //
        gatewayUserPanel.add(gatewayUserLbl);
        gatewayUserPanel.add(gatewayUserField);
        //
        gatewayPanel.setLayout(new BorderLayout());
        gatewayPanel.setBorder(new TitledBorder(EMAIL_GATEWAY));
        gatewayPanel.add(gatewyp, BorderLayout.NORTH);
        gatewayPanel.add(gatewayUserPanel, BorderLayout.CENTER);
        gatewayPanel.add(gatewayPwdPanel, BorderLayout.SOUTH);
        //
        //
        JPanel formatPanel = new JPanel();
        formatPanel.setLayout(new BorderLayout());
        formatPanel.setBorder(new TitledBorder(EMAIL_FORMAT));
        formatPanel.add(textRB, BorderLayout.NORTH);
        formatPanel.add(htmlRB, BorderLayout.CENTER);
        //
        JPanel combinedFormatGatewayPanel = new JPanel();
        combinedFormatGatewayPanel.setLayout(new BorderLayout());
        combinedFormatGatewayPanel.add(gatewayPanel, BorderLayout.CENTER);
        combinedFormatGatewayPanel.add(formatPanel, BorderLayout.EAST);
        //
        noticePanel.setLayout(new BorderLayout());
        noticePanel.setBorder(new TitledBorder(EMAIL_SETTINGS));
        noticePanel.add(sendEmailLbl, BorderLayout.NORTH);
        noticePanel.add(sendEmailBx, BorderLayout.CENTER);
        //
        emailPanel.setLayout(new BorderLayout());
        emailPanel.setBorder(new TitledBorder(EMAIL_ADDRESSES));
        emailPanel.add(emailPane, BorderLayout.CENTER);
        emailPanel.add(emailCPpanel, BorderLayout.EAST);
        //
        completeEmailPanel.setLayout(new BorderLayout());
        completeEmailPanel.add(noticePanel, BorderLayout.NORTH);
        completeEmailPanel.add(emailPanel, BorderLayout.CENTER);
        completeEmailPanel.add(combinedFormatGatewayPanel, BorderLayout.SOUTH);

        tp.addTab(Messages.getString("DocSearch.hndlersTab"), null, hndlerPanel, Messages.getString("DocSearch.hndlersTabInf"));
        tp.addTab(Messages.getString("DocSearch.guiStuff"), null, uiWrap, Messages.getString("DocSearch.guiStuffInf"));
        tp.addTab(DS_DIR_TAB, null, dp, DS_DIR_EXP);
        tp.addTab(NOTIFICATIONS, null, completeEmailPanel, NOTIFICATIONS);
        //
        panels = new JPanel[numPanels];
        for (int i = 0; i < numPanels; i++)
            panels[i] = new JPanel();
        panels[0].add(tp);
        //
        panels[numPanels - 1].add(bp);
        //
        // NOW PLACE THE GUI ONTO A GRIDBAG
        // put in the gridbag stuff
        getContentPane().setLayout(new GridLayout(1, numPanels));
        GridBagLayout gridbaglayout = new GridBagLayout();
        GridBagConstraints gridbagconstraints = new GridBagConstraints();
        getContentPane().setLayout(gridbaglayout);
        //
        for (int i = 0; i < numPanels; i++) {
            gridbagconstraints.fill = 1;
            gridbagconstraints.insets = new Insets(1, 1, 1, 1);
            gridbagconstraints.gridx = 0;
            gridbagconstraints.gridy = i;
            gridbagconstraints.gridwidth = 1;
            gridbagconstraints.gridheight = 1;
            gridbagconstraints.weightx = 0.0D;
            gridbagconstraints.weighty = 0.0D;
            gridbaglayout.setConstraints(panels[i], gridbagconstraints);
            getContentPane().add(panels[i]);
        }

    }

    public void init() {
        //
        setLafs();
        setList();
        defaultHndlrField.setText(monitor.getDefaultHndlr());
        dsDirField.setText(fEnv.getIndexDirectory());
        tempDirField.setText(monitor.tempDir);
        workingDirField.setText(fEnv.getWorkingDirectory());
        if (monitor.emailFormat.equals(TEXT_FORMAT))
            textRB.setSelected(true);
        else if (monitor.emailFormat.equals(HTML_FORMAT))
            htmlRB.setSelected(true);
        else
            textRB.setSelected(true);
        maxField.setText("" + monitor.getMaxNumHitsShown());
        //
        Object[] emls = monitor.getEmails();
        if (emls != null)
            emailList.setListData(emls);
        gateWayField.setText(monitor.gateway);
        gatewayPwdField.setText(monitor.gatewayPwd);
        gatewayUserField.setText(monitor.gatewayUser);
        if (monitor.sendEmailNotice.equals("true"))
            sendEmailBx.setSelected(true);
        cb();
        //
        pack();
        // center this dialog
        Rectangle frameSize = getBounds();
        Dimension screenD = Toolkit.getDefaultToolkit().getScreenSize();
        int screenWidth = screenD.width;
        int screenHeight = screenD.height;
        int newX = 0;
        int newY = 0;
        if (screenWidth > frameSize.width)
            newX = (screenWidth - frameSize.width) / 2;
        if (screenHeight > frameSize.height)
            newY = (screenHeight - frameSize.height) / 2;
        if ((newX != 0) || (newY != 0))
            setLocation(newX, newY);
        if (monitor.getLoadExternal())
            loadExternal.setSelected(true);
        else
            loadExternal.setSelected(false);
        long mfs = (monitor.getMaxFileSize() / 1024);
        maxSizeField.setText("" + mfs);
    }

    @Override
	public void actionPerformed(ActionEvent actionevent) {
        String s = actionevent.getActionCommand();
        if (s.equals(APPLY)) {
            returnInt = tp.getSelectedIndex();
            String newIndexDir = dsDirField.getText().trim();
            if (returnInt == 2 && newIndexDir.equals("")) {
                monitor.showMessage(I18n.getString("error"), PROVIDE_IDX_DIR);
            }
            else {
                confirmed = true;
                this.setVisible(false);
            }
        }
        // end for ok
        else if (s.equals(ADD)) {
            NewHandlerDialog nhd = new NewHandlerDialog(monitor, NEW_HANDLER, true);
            nhd.init();
            nhd.setVisible(true);
            if (nhd.returnBool) {
                //
                DocTypeHandler dh = new DocTypeHandler(nhd.extField.getText(), nhd.descField.getText(), nhd.appField.getText());
                monitor.handlerList.add(dh);
                setList();
            }
        } // end for adding a handler
        else if (s.equals(REMOVE)) {
            int chosen = handlerList.getSelectedIndex();
            if (chosen != -1) {
                removeItemAt(chosen);
                monitor.handlerList.remove(chosen);
                setList();
            }
        } // end for adding a handler
        else if (s.equals(EDIT)) {
            int chosen = handlerList.getSelectedIndex();
            if (chosen != -1) {
                //
                NewHandlerDialog nhd = new NewHandlerDialog(monitor, EDIT_HANDLER, true);
                // set the values of the selected item
                nhd.init();
                nhd.setDTH(monitor.handlerList.get(chosen));
                nhd.setVisible(true);
                if (nhd.returnBool) {
                    DocTypeHandler dh = monitor.handlerList.get(chosen);
                    dh = new DocTypeHandler(nhd.extField.getText(), nhd.descField.getText(), nhd.appField.getText());
                    monitor.handlerList.set(chosen, dh);
                    setList();
                }
            } // end for item chosen
        } // end for editing a handler
        else if (s.equals(BROWSE)) {
            JFileChooser fdo = new JFileChooser();
            fdo.setCurrentDirectory(new File(fEnv.getUserHome()));
            fdo.setFileSelectionMode(JFileChooser.FILES_ONLY);
            int fileGotten = fdo.showDialog(this, SELECT);
            if (fileGotten == JFileChooser.APPROVE_OPTION) {
                File file = fdo.getSelectedFile();
                String fNa = file.toString();
                defaultHndlrField.setText(fNa);
            }
        }
        //
        else if (s.equals(SELECT_WORKING_DIR)) {
            JFileChooser fdo = new JFileChooser();
            fdo.setCurrentDirectory(new File(fEnv.getWorkingDirectory()));
            fdo.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            int fileGotten = fdo.showDialog(this, SELECT);
            if (fileGotten == JFileChooser.APPROVE_OPTION) {
                File file = fdo.getSelectedFile();
                String fNa = file.toString();
                workingDirField.setText(fNa);
            }
        } else if (s.equals(SELECT_TEMP_DIR)) {
            JFileChooser fdo = new JFileChooser();
            fdo.setCurrentDirectory(new File(fEnv.getUserHome()));
            fdo.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            int fileGotten = fdo.showDialog(this, SELECT);
            if (fileGotten == JFileChooser.APPROVE_OPTION) {
                File file = fdo.getSelectedFile();
                String fNa = file.toString();
                tempDirField.setText(fNa);
            }
        } else if (s.equals(CANCEL)) {
            confirmed = false;
            this.setVisible(false);
        } else if (s.equals(REMOVE_EMAIL)) {
            int itemNo = emailList.getSelectedIndex();
            if (itemNo != -1)
                removeEmailItem(itemNo);
        } else if (s.equals(ADD_EMAIL)) {
            DsEmail me = new DsEmail(this, ADD + " " + EMAIL_ADDRESS, true);
            me.init();
            me.setVisible(true);
            if (me.confirmed) {
                //
                String em = me.nameField.getText();
                if (!em.equals(""))
                    addEmail(em);
            } // end for me
        } else if (s.equals(EDIT_EMAIL)) {
            int itemNo = emailList.getSelectedIndex();
            if (itemNo != -1) {
                DsEmail me = new DsEmail(this, EDIT + " " + EMAIL_ADDRESS, true);
                me.init();
                me.nameField.setText(monitor.getEmail(itemNo));
                me.setVisible(true);
                if (me.confirmed) {
                    String newEm = me.nameField.getText();
                    if (!newEm.equals(""))
                        replaceEmail(itemNo, newEm);
                }
            }
        } else if (s.equals(SELECT_DS_DIR)) {
            JFileChooser fdo = new JFileChooser();
            fdo.setCurrentDirectory(new File(fEnv.getIndexDirectory()));
            fdo.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            int fileGotten = fdo.showDialog(this, SELECT);
            if (fileGotten == JFileChooser.APPROVE_OPTION) {
                File file = fdo.getSelectedFile();
                String fNa = file.toString();
                dsDirField.setText(fNa);
            }
        }
    }

    public void setList() {
        int numHndlrs = monitor.handlerList.size();
        if (numHndlrs > 0) {
            String listItems[] = new String[numHndlrs];
            Iterator<DocTypeHandler> it = monitor.handlerList.iterator();
            int curI = 0;
            while (it.hasNext()) {
                DocTypeHandler dh = it.next();
                listItems[curI] = dh.descName();
                curI++;
            }
            handlerList.setListData(listItems);
        }
    } // end for setlist

    public void removeItemAt(int removeItemNum) {
        if (removeItemNum != -1) {
            int newNum = handlerList.getModel().getSize() - 1;
            // System.out.println("Item to skip:
            // "+(String)AllPages.getModel().getElementAt(removeItemNum));
            if (newNum == 0)
                handlerList.removeAll();
            else if (newNum > 0) {
                String[] nData = new String[newNum];
                int curAd = 0;
                for (int i = 0; i < newNum + 1; i++) {
                    if (i != removeItemNum) {
                        nData[curAd] = (String) handlerList.getModel().getElementAt(i);
                        curAd++;
                    }
                } // end for adding
                handlerList.setListData(nData);
            } // end if more than one item
        } // end if not zero
    } // end for removeItemAt

    public void setLafs() {
        int matchInt = 0;
        boolean foundMtch = false;
        ArrayList<String> lafs = getAllAvailableLookAndFeel();
        if (! lafs.isEmpty()) {
            // int numLafs=lafs.size();
            Iterator<String> it = lafs.iterator();
            String laf;
            int curLF = 1;
            while (it.hasNext()) {
                laf = it.next();
                if (! monitor.lafChosen.equals("")) {
                    if (laf.toLowerCase().equals(monitor.getLafChosen().toLowerCase())) {
                        matchInt = curLF;
                        foundMtch = true;
                    }
                }
                uiChoice.addItem(laf);
                curLF++;
            }
        }
        if (foundMtch) {
            uiChoice.setSelectedIndex(matchInt);
        }
    }

    public void cb() {
        if (!sendEmailBx.isSelected()) {
            addEmailButton.setEnabled(false);
            removeEmailButton.setEnabled(false);
            editEmailButton.setEnabled(false);
            gatewayUserField.setEnabled(false);
            gatewayPwdField.setEnabled(false);
            gateWayField.setEnabled(false);
            emailList.setEnabled(false);
            textRB.setEnabled(false);
            htmlRB.setEnabled(false);
        } else {
            addEmailButton.setEnabled(true);
            removeEmailButton.setEnabled(true);
            editEmailButton.setEnabled(true);
            gatewayUserField.setEnabled(true);
            gatewayPwdField.setEnabled(true);
            gateWayField.setEnabled(true);
            emailList.setEnabled(true);
            textRB.setEnabled(true);
            htmlRB.setEnabled(true);
        }
    }

    class CbListener implements ActionListener {
        @Override
		public void actionPerformed(ActionEvent e) {
            // String CMD=e.getActionCommand();
            cb();
        } // end of action
    } // end for radio listener

    public void addEmail(String toAdd) {
        // adds email to our list
        monitor.addEmail(toAdd);
        emailList.setListData(monitor.getEmails());
    } // end for addEmail

    /**
     * Gets all available Look and Feels
     *
     * @return  List with Classname of Look and Feel
     */
    private ArrayList<String> getAllAvailableLookAndFeel() {
        ArrayList<String> lafList = new ArrayList<String>();

        // get all LaF
        LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels();
        for (LookAndFeelInfo laf : lafs) {
        	lafList.add(laf.getClassName());

        	logger.debug("Look and Feel : " + laf.getClassName());
        }
        return lafList;
    }

    public void replaceEmail(int idx, String toRep) {
        monitor.setEmail(idx, toRep);
        emailList.setListData(monitor.getEmails());
    }

    public void removeEmailItem(int toRem) {
        monitor.removeEmail(toRem);
        emailList.setListData(monitor.getEmails());
    }

    public String getGateWayFieldText() {
        return gateWayField.getText();
    }

    public String gatewayPwdFieldText() {
        return new String(gatewayPwdField.getPassword());
    }

    public String gatewayUserFieldText() {
        return gatewayUserField.getText();
    }

    public String getTmpFieldText() {
        return tempDirField.getText();
    }

    public String getDsDirFieldText() {
        return dsDirField.getText();
    }

    public String workingDirFieldText() {
        return workingDirField.getText();
    }

    public String maxSizeField() {
        return maxSizeField.getText();
    }

    public String maxFieldText() {
        return maxField.getText();
    }

    public String defltHndlrText() {
        return defaultHndlrField.getText();
    }

    public String lafSelected() {
        return (String) uiChoice.getModel().getSelectedItem();
    }

    public boolean sendEmailBxSelected() {
        return sendEmailBx.isSelected();
    }

    public boolean textRBSelected() {
        return textRB.isSelected();
    }

    public boolean copyDirFilesSelected() {
        return copyDirFiles.isSelected();
    }

    public boolean loadExternalSelected() {
        return loadExternal.isSelected();
    }

    public int getReturnInt() {
        return returnInt;
    }

    public boolean getConfirmed() {
        return confirmed;
    }
}


text:
namespace mscl {

public class Connection : global::System.IDisposable {
  private global::System.Runtime.InteropServices.HandleRef swigCPtr;
  protected bool swigCMemOwn;

  internal Connection(global::System.IntPtr cPtr, bool cMemoryOwn) {
    swigCMemOwn = cMemoryOwn;
    swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
  }

  internal static global::System.Runtime.InteropServices.HandleRef getCPtr(Connection obj) {
    return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
  }

  ~Connection() {
    Dispose(false);
  }

  public void Dispose() {
    Dispose(true);
    global::System.GC.SuppressFinalize(this);
  }

  protected virtual void Dispose(bool disposing) {
    lock(this) {
      if (swigCPtr.Handle != global::System.IntPtr.Zero) {
        if (swigCMemOwn) {
          swigCMemOwn = false;
          msclPINVOKE.delete_Connection(swigCPtr);
        }
        swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
      }
    }
  }

  public Connection() : this(msclPINVOKE.new_Connection(), true) {
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
  }

  public static Connection Serial(string port, uint baudRate) {
    Connection ret = new Connection(msclPINVOKE.Connection_Serial__SWIG_0(port, baudRate), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public static Connection Serial(string port) {
    Connection ret = new Connection(msclPINVOKE.Connection_Serial__SWIG_1(port), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public static Connection TcpIp(string serverAddress, ushort serverPort, string interfaceAddress) {
    Connection ret = new Connection(msclPINVOKE.Connection_TcpIp__SWIG_0(serverAddress, serverPort, interfaceAddress), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public static Connection TcpIp(string serverAddress, ushort serverPort) {
    Connection ret = new Connection(msclPINVOKE.Connection_TcpIp__SWIG_1(serverAddress, serverPort), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public static Connection WebSocket(string host, ushort port) {
    Connection ret = new Connection(msclPINVOKE.Connection_WebSocket(host, port), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public static Connection Mock() {
    Connection ret = new Connection(msclPINVOKE.Connection_Mock(), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public string description() {
    string ret = msclPINVOKE.Connection_description(swigCPtr);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public string port() {
    string ret = msclPINVOKE.Connection_port(swigCPtr);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public Connection.ConnectionType type() {
    Connection.ConnectionType ret = (Connection.ConnectionType)msclPINVOKE.Connection_type(swigCPtr);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public void disconnect() {
    msclPINVOKE.Connection_disconnect(swigCPtr);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
  }

  public void reconnect() {
    msclPINVOKE.Connection_reconnect(swigCPtr);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
  }

  public void write(Bytes bytes) {
    msclPINVOKE.Connection_write(swigCPtr, Bytes.getCPtr(bytes));
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
  }

  public void writeStr(string bytes) {
    msclPINVOKE.Connection_writeStr(swigCPtr, bytes);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
  }

  public void clearBuffer() {
    msclPINVOKE.Connection_clearBuffer(swigCPtr);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
  }

  public uint byteReadPos() {
    uint ret = msclPINVOKE.Connection_byteReadPos(swigCPtr);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public uint byteAppendPos() {
    uint ret = msclPINVOKE.Connection_byteAppendPos(swigCPtr);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public void rawByteMode(bool enable) {
    msclPINVOKE.Connection_rawByteMode__SWIG_0(swigCPtr, enable);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
  }

  public bool rawByteMode() {
    bool ret = msclPINVOKE.Connection_rawByteMode__SWIG_1(swigCPtr);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public Bytes getRawBytes(uint timeout, uint maxBytes, uint minBytes) {
    Bytes ret = new Bytes(msclPINVOKE.Connection_getRawBytes__SWIG_0(swigCPtr, timeout, maxBytes, minBytes), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public Bytes getRawBytes(uint timeout, uint maxBytes) {
    Bytes ret = new Bytes(msclPINVOKE.Connection_getRawBytes__SWIG_1(swigCPtr, timeout, maxBytes), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public Bytes getRawBytes(uint timeout) {
    Bytes ret = new Bytes(msclPINVOKE.Connection_getRawBytes__SWIG_2(swigCPtr, timeout), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public Bytes getRawBytes() {
    Bytes ret = new Bytes(msclPINVOKE.Connection_getRawBytes__SWIG_3(swigCPtr), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public string getRawBytesStr(uint timeout, uint maxBytes, uint minBytes) {
    string ret = msclPINVOKE.Connection_getRawBytesStr__SWIG_0(swigCPtr, timeout, maxBytes, minBytes);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public string getRawBytesStr(uint timeout, uint maxBytes) {
    string ret = msclPINVOKE.Connection_getRawBytesStr__SWIG_1(swigCPtr, timeout, maxBytes);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public string getRawBytesStr(uint timeout) {
    string ret = msclPINVOKE.Connection_getRawBytesStr__SWIG_2(swigCPtr, timeout);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public string getRawBytesStr() {
    string ret = msclPINVOKE.Connection_getRawBytesStr__SWIG_3(swigCPtr);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public Bytes getRawBytesWithPattern(Bytes pattern, uint timeout) {
    Bytes ret = new Bytes(msclPINVOKE.Connection_getRawBytesWithPattern__SWIG_0(swigCPtr, Bytes.getCPtr(pattern), timeout), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public Bytes getRawBytesWithPattern(Bytes pattern) {
    Bytes ret = new Bytes(msclPINVOKE.Connection_getRawBytesWithPattern__SWIG_1(swigCPtr, Bytes.getCPtr(pattern)), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public void debugMode(bool enable) {
    msclPINVOKE.Connection_debugMode__SWIG_0(swigCPtr, enable);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
  }

  public bool debugMode() {
    bool ret = msclPINVOKE.Connection_debugMode__SWIG_1(swigCPtr);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public ConnectionDebugDataVec getDebugData(uint timeout) {
    ConnectionDebugDataVec ret = new ConnectionDebugDataVec(msclPINVOKE.Connection_getDebugData__SWIG_0(swigCPtr, timeout), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public ConnectionDebugDataVec getDebugData() {
    ConnectionDebugDataVec ret = new ConnectionDebugDataVec(msclPINVOKE.Connection_getDebugData__SWIG_1(swigCPtr), true);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }

  public void updateBaudRate(uint baudRate) {
    msclPINVOKE.Connection_updateBaudRate(swigCPtr, baudRate);
    if (msclPINVOKE.SWIGPendingException.Pending) throw msclPINVOKE.SWIGPendingException.Retrieve();
  }

  public enum ConnectionType {
    connectionType_serial = 0,
    connectionType_tcp = 1,
    connectionType_webSocket = 2,
    connectionType_unixSocket = 3
  }

}

}

redpajama_set_name: RedPajamaGithub


text:
local base64 = require "base64"
local remy = require "remy"
local lighty = require "lighty"

local utils = {}

utils.parseargs = function()
    local get = {}
    if (lighty.env["uri.query"]) then
      -- split the query-string
      for k, v in string.gmatch(lighty.env["uri.query"], "(%w+)=(.+)") do
        get[k] = v
      end
    end
    return get
end

-- TODO: implement all functions from mod_lua's request_rec
local request = {
	-- ENCODING/DECODING FUNCTIONS
	base64_decode = function(_,...) return base64.decode(...) end,
	base64_encode = function(_,...) return base64.encode(...) end,
	sha1  = function(_,...) return remy.sha1(...) end,
	-- REQUEST PARSING FUNCTIONS
	parseargs = function(_) return utils.parseargs(), {} end,
	parsebody = function(_) return {}, {} end,
	-- REQUEST RESPONSE FUNCTIONS
	puts = function(_,...) remy.print(...) end,
	write = function(_,...) remy.print(...) end
}

local M = {
  mode = "lighttpd",
  request = request
}

function M.init()
	local r = request
	local filename = lighty.env["physical.path"]
	local uri = lighty.env["uri.path"]
	apache2.version = M.mode
	r = remy.loadrequestrec(r)
	r.headers_out = lighty.header
	r.headers_in = lighty.request
	local auth = base64.decode((r.headers_in["Authorization"] or ""):sub(7))
	local _,_,user,pass = auth:find("([^:]+)%:([^:]+)")
	r.method = lighty.env["request.method"]
	r.args = lighty.env["uri.query"]
	--r.args = remy.splitstring(lighty.env['request.uri'],'?')
	r.banner = M.mode
  r.basic_auth_pw = pass
	r.canonical_filename = filename
	r.context_document_root = lighty.env["physical.doc-root"]
	r.document_root = lighty.env["physical.doc-root"]
	r.filename = filename
	r.hostname = lighty.env["uri.authority"]
	--r.port = ???
	r.protocol = lighty.env["request.protocol"]
	r.range = r.headers_in["Range"]
	r.server_name = r.hostname
	r.the_request = r.method.." "..lighty.env["request.uri"].." "..r.protocol
	r.unparsed_uri = lighty.env["request.orig-uri"]
	r.uri = uri
	r.user = user
	r.useragent_ip = lighty.env['request.remote-ip']
end

function M.contentheader(content_type)
	request.content_type = content_type
	lighty.header["Content-Type"] = content_type
end

function M.finish(code)
  lighty.content = { remy.responsetext }
end

return M


text:
import * as async from 'async';
import * as _ from 'lodash';
import 'source-map-support/register';

// This has been changed in favor of @sendgrid.  To use nodemail, change the
// sending function from `.send` to `.sendMail`.
// import * as nodemailer from nodemailer';
import request from 'request';
import { Lock } from './lock';
import logger from './logger';
import { MessageBroker } from './messagebroker';
import { Email } from './model';
import { Storage } from './storage';
export interface Recipient {
  copayerId: string;
  emailAddress: string;
  language: string;
  unit: string;
}

const Mustache = require('mustache');
const fs = require('fs');
const path = require('path');
const Utils = require('./common/utils');
const Defaults = require('./common/defaults');
const Constants = require('./common/constants');
const defaultRequest = require('request');

const EMAIL_TYPES = {
  NewCopayer: {
    filename: 'new_copayer',
    notifyDoer: false,
    notifyOthers: true
  },
  WalletComplete: {
    filename: 'wallet_complete',
    notifyDoer: true,
    notifyOthers: true
  },
  NewTxProposal: {
    filename: 'new_tx_proposal',
    notifyDoer: false,
    notifyOthers: true
  },
  NewOutgoingTx: {
    filename: 'new_outgoing_tx',
    notifyDoer: true,
    notifyOthers: true
  },
  NewIncomingTx: {
    filename: 'new_incoming_tx',
    notifyDoer: true,
    notifyOthers: true
  },
  TxProposalFinallyRejected: {
    filename: 'txp_finally_rejected',
    notifyDoer: false,
    notifyOthers: true
  },
  TxConfirmation: {
    filename: 'tx_confirmation',
    notifyDoer: true,
    notifyOthers: false
  }
};

export class EmailService {
  defaultLanguage: string;
  defaultUnit: string;
  templatePath: string;
  publicTxUrlTemplate: string;
  subjectPrefix: string;
  from: string;
  availableLanguages: string[];
  storage: Storage;
  messageBroker: MessageBroker;
  lock: Lock;
  mailer: any;
  request: request.RequestAPI<any, any, any>;
  //  mailer: nodemailer.Transporter;

  start(opts, cb) {
    opts = opts || {};
    this.request = opts.request || defaultRequest;

    const _readDirectories = (basePath, cb) => {
      fs.readdir(basePath, (err, files) => {
        if (err) return cb(err);
        async.filter(
          files,
          (file, next) => {
            fs.stat(path.join(basePath, file), (err, stats) => {
              return next(!err && stats.isDirectory());
            });
          },
          dirs => {
            return cb(null, dirs);
          }
        );
      });
    };

    opts.emailOpts = opts.emailOpts || {};

    this.defaultLanguage = opts.emailOpts.defaultLanguage || 'en';
    this.defaultUnit = opts.emailOpts.defaultUnit || 'btc';
    logger.info('Email templates at:' + (opts.emailOpts.templatePath || __dirname + '/../../templates') + '/');
    this.templatePath = path.normalize((opts.emailOpts.templatePath || __dirname + '/../../templates') + '/');

    this.publicTxUrlTemplate = opts.emailOpts.publicTxUrlTemplate || {};
    this.subjectPrefix = opts.emailOpts.subjectPrefix || '[Wallet service]';
    this.from = opts.emailOpts.from;

    async.parallel(
      [
        done => {
          _readDirectories(this.templatePath, (err, res) => {
            this.availableLanguages = res;
            done(err);
          });
        },
        done => {
          if (opts.storage) {
            this.storage = opts.storage;
            done();
          } else {
            this.storage = new Storage();
            this.storage.connect(opts.storageOpts, done);
          }
        },
        done => {
          this.messageBroker = opts.messageBroker || new MessageBroker(opts.messageBrokerOpts);
          this.messageBroker.onMessage(_.bind(this.sendEmail, this));
          done();
        },
        done => {
          this.lock = opts.lock || new Lock(this.storage);
          done();
        },
        done => {
          this.mailer = opts.mailer; // || nodemailer.createTransport(opts.emailOpts);
          done();
        }
      ],
      err => {
        if (err) {
          logger.error(err);
        }
        return cb(err);
      }
    );
  }

  _compileTemplate(template, extension) {
    const lines = template.split('\n');
    if (extension == '.html') {
      lines.unshift('');
    }
    return {
      subject: lines[0],
      body: _.tail(lines).join('\n')
    };
  }

  _readTemplateFile(language, filename, cb) {
    const fullFilename = path.join(this.templatePath, language, filename);
    fs.readFile(fullFilename, 'utf8', (err, template) => {
      if (err) {
        return cb(new Error('Could not read template file ' + fullFilename + err));
      }
      return cb(null, template);
    });
  }

  // TODO: cache for X minutes
  _loadTemplate(emailType, recipient, extension, cb) {
    this._readTemplateFile(recipient.language, emailType.filename + extension, (err, template) => {
      if (err) return cb(err);
      return cb(null, this._compileTemplate(template, extension));
    });
  }

  _applyTemplate(template, data, cb) {
    if (!data) return cb(new Error('Could not apply template to empty data'));

    let error;
    const result = _.mapValues(template, t => {
      try {
        return Mustache.render(t, data);
      } catch (e) {
        logger.error('Could not apply data to template', e);
        error = e;
      }
    });
    if (error) return cb(error);
    return cb(null, result);
  }

  _getRecipientsList(notification, emailType, cb) {
    this.storage.fetchWallet(notification.walletId, (err, wallet) => {
      if (err) return cb(err);

      this.storage.fetchPreferences(notification.walletId, null, (err, preferences) => {
        if (err) return cb(err);
        if (_.isEmpty(preferences)) return cb(null, []);

        const usedEmails = {};
        const recipients = _.compact(
          _.map(preferences, p => {
            if (!p.email || usedEmails[p.email]) return;

            usedEmails[p.email] = true;
            if (notification.creatorId == p.copayerId && !emailType.notifyDoer) return;
            if (notification.creatorId != p.copayerId && !emailType.notifyOthers) return;
            if (!_.includes(this.availableLanguages, p.language)) {
              if (p.language) {
                logger.warn('Language for email "' + p.language + '" not available.');
              }
              p.language = this.defaultLanguage;
            }

            let unit;
            if (wallet.coin != Defaults.COIN) {
              switch (wallet.coin) {
                case 'pax':
                  unit = 'usdp'; // backwards compatibility
                  break;
                default:
                  unit = wallet.coin;
              }
            } else {
              unit = p.unit || this.defaultUnit;
            }

            return {
              copayerId: p.copayerId,
              emailAddress: p.email,
              language: p.language,
              unit
            };
          })
        );

        return cb(null, recipients);
      });
    });
  }

  async _getDataForTemplate(notification, recipient, cb) {
    const UNIT_LABELS = {
      btc: 'BTC',
      bit: 'bits',
      bch: 'BCH',
      eth: 'ETH',
      matic: 'MATIC',
      xrp: 'XRP',
      doge: 'DOGE',
      ltc: 'LTC',
      usdc: 'USDC',
      usdp: 'USDP',
      gusd: 'GUSD',
      busd: 'BUSD',
      wbtc: 'WBTC',
      dai: 'DAI',
      shib: 'SHIB',
      ape: 'APE',
      euroc: 'EUROC',
      usdt: 'USDT'
    };

    const data = _.cloneDeep(notification.data);
    data.subjectPrefix = _.trim(this.subjectPrefix) + ' ';
    if (data.amount) {
      try {
        let unit = recipient.unit.toLowerCase();
        let label = UNIT_LABELS[unit];
        let opts = {} as any;
        if (data.tokenAddress) {
          const tokenAddress = data.tokenAddress.toLowerCase();
          if (Constants.ETH_TOKEN_OPTS[tokenAddress]) {
            unit = Constants.ETH_TOKEN_OPTS[tokenAddress].symbol.toLowerCase();
            label = UNIT_LABELS[unit];
          } else if (Constants.MATIC_TOKEN_OPTS[tokenAddress]) {
            unit = Constants.MATIC_TOKEN_OPTS[tokenAddress].symbol.toLowerCase();
            label = UNIT_LABELS[unit];
          } else {
            let customTokensData;
            try {
              customTokensData = await this.getTokenData(data.address.coin);
            } catch (error) {
              return cb(new Error('Could not get custom tokens data'));
            }
            if (customTokensData && customTokensData[tokenAddress]) {
              unit = customTokensData[tokenAddress].symbol.toLowerCase();
              label = unit.toUpperCase();
              opts.toSatoshis = 10 ** customTokensData[tokenAddress].decimals;
              opts.decimals = {
                maxDecimals: 6,
                minDecimals: 2
              };
            } else {
              return cb(new Error(`Email Notifications for unsupported tokens are not allowed: ${tokenAddress}`));
            }
          }
        }
        data.amount = Utils.formatAmount(+data.amount, unit, opts) + ' ' + label;
      } catch (ex) {
        return cb(new Error('Could not format amount' + ex));
      }
    }

    this.storage.fetchWallet(notification.walletId, (err, wallet) => {
      if (err) return cb(err);
      if (!wallet) return cb('no wallet');
      data.walletId = wallet.id;
      data.walletName = wallet.name;
      data.walletM = wallet.m;
      data.walletN = wallet.n;
      const copayer = wallet.copayers.find(c => c.id == notification.creatorId);
      if (copayer) {
        data.copayerId = copayer.id;
        data.copayerName = copayer.name;
      }

      if (notification.type == 'TxProposalFinallyRejected' && data.rejectedBy) {
        const rejectors = _.map(data.rejectedBy, copayerId => {
          const copayer = wallet.copayers.find(c => c.id == copayerId);
          return copayer.name;
        });
        data.rejectorsNames = rejectors.join(', ');
      }

      if (_.includes(['NewIncomingTx', 'NewOutgoingTx'], notification.type) && data.txid) {
        const urlTemplate = this.publicTxUrlTemplate[wallet.chain]?.[wallet.network];
        if (urlTemplate) {
          try {
            data.urlForTx = Mustache.render(urlTemplate, data);
          } catch (ex) {
            logger.warn('Could not render public url for tx', ex);
          }
        } else {
          logger.warn(`Could not find template for chain "${wallet.chain}" on network "${wallet.network}"`);
        }
      }

      return cb(null, data);
    });
  }

  _send(email, cb) {
    const mailOptions = {
      from: email.from,
      to: email.to,
      subject: email.subject,
      text: email.bodyPlain,
      html: undefined
    };
    if (email.bodyHtml) {
      mailOptions.html = email.bodyHtml;
    }
    this.mailer
      .send(mailOptions)
      .then(result => {
        logger.debug('Message sent: ', result || '');
        return cb(null, result);
      })
      .catch(err => {
        let errStr;
        try {
          errStr = err.toString().substr(0, 100);
        } catch (e) {}

        logger.warn('An error occurred when trying to send email to ' + email.to, errStr || err);
        return cb(err);
      });
  }

  _readAndApplyTemplates(notification, emailType, recipientsList: Recipient[], cb) {
    async.map(
      recipientsList,
      (recipient, next) => {
        async.waterfall(
          [
            next => {
              this._getDataForTemplate(notification, recipient, next);
            },
            (data, next) => {
              async.map(
                ['plain', 'html'],
                (type, next) => {
                  this._loadTemplate(emailType, recipient, '.' + type, (err, template) => {
                    if (err && type == 'html') return next();
                    if (err) return next(err);
                    this._applyTemplate(template, data, (err, res) => {
                      return next(err, [type, res]);
                    });
                  });
                },
                (err, res: any) => {
                  return next(err, _.fromPairs(res.filter(Boolean)));
                }
              );
            },
            (result, next) => {
              next(null, result);
            }
          ],
          (err, res) => {
            next(err, [recipient.language, res]);
          }
        );
      },
      (err, res: any) => {
        return cb(err, _.fromPairs(res.filter(Boolean)));
      }
    );
  }

  _checkShouldSendEmail(notification, cb) {
    if (notification.type != 'NewTxProposal') return cb(null, true);
    this.storage.fetchWallet(notification.walletId, (err, wallet) => {
      return cb(err, wallet.m > 1);
    });
  }

  sendEmail(notification, cb) {
    cb = cb || function() {};

    const emailType = EMAIL_TYPES[notification.type];
    if (!emailType) return cb();

    this._checkShouldSendEmail(notification, (err, should) => {
      if (err) return cb(err);
      if (!should) return cb();

      this._getRecipientsList(notification, emailType, (err, recipientsList: Recipient[]) => {
        if (_.isEmpty(recipientsList)) return cb();

        // TODO: Optimize so one process does not have to wait until all others are done
        // Instead set a flag somewhere in the db to indicate that this process is free
        // to serve another request.
        this.lock.runLocked('email-' + notification.id, {}, cb, cb => {
          this.storage.fetchEmailByNotification(notification.id, (err, email) => {
            if (err) return cb(err);
            if (email) return cb();

            async.waterfall(
              [
                next => {
                  this._readAndApplyTemplates(notification, emailType, recipientsList, next);
                },
                (contents, next) => {
                  async.map(
                    recipientsList,
                    (recipient, next) => {
                      const content = contents[recipient.language];
                      const email = Email.create({
                        walletId: notification.walletId,
                        copayerId: recipient.copayerId,
                        from: this.from,
                        to: recipient.emailAddress,
                        subject: content.plain.subject,
                        bodyPlain: content.plain.body,
                        bodyHtml: content.html ? content.html.body : null,
                        notificationId: notification.id
                      });
                      this.storage.storeEmail(email, err => {
                        return next(err, email);
                      });
                    },
                    next
                  );
                },
                (emails, next) => {
                  async.each(
                    emails,
                    (email: any, next) => {
                      this._send(email, err => {
                        if (err) {
                          email.setFail();
                        } else {
                          email.setSent();
                        }
                        this.storage.storeEmail(email, next);
                      });
                    },
                    err => {
                      return next();
                    }
                  );
                }
              ],
              err => {
                if (err) {
                  let errStr;
                  try {
                    errStr = err.toString().substr(0, 100);
                  } catch (e) {}

                  logger.warn('An error ocurred generating email notification', errStr || err);
                }
                return cb(err);
              }
            );
          });
        });
      });
    });
  }

  getTokenData(chain) {
    return new Promise((resolve, reject) => {
      const chainIdMap = {
        eth: 1,
        matic: 137
      };
      // Get tokens
      this.request(
        {
          url: `https://bitpay.api.enterprise.1inch.exchange/v3.0/${chainIdMap[chain]}/tokens`,
          method: 'GET',
          json: true,
          headers: {
            'Content-Type': 'application/json'
          }
        },
        (err, data: any) => {
          if (err) return reject(err);
          return resolve(data.body.tokens);
        }
      );
    });
  }
}

module.exports = EmailService;


text:
import { ADD_NODES } from "../../../constants";
import { manyBodyStrengths } from "./initialize";
import { initialState, defaultStrength } from "./index";
import getStateConstant from "../../../utils/getStateConstant";

export default ({ strength = defaultStrength } = {}) => {
  strength = getStateConstant(strength);
  return (state = initialState, action) => {
    if (action.type === ADD_NODES) {
      return manyBodyStrengths(strength)(state);
    }

    return state;
  };
};


text:
#include "postgres.h"

#include "access/gin.h"
#include "access/hash.h"
#include "access/stratnum.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "utils/builtins.h"
#include "utils/jsonb.h"

typedef struct PathHashStack
{
	uint32		hash;
	struct PathHashStack *parent;
} PathHashStack;

static Datum make_text_key(char flag, const char *str, int len);
static Datum make_scalar_key(const JsonbValue *scalarVal, bool is_key);

/*
 *
 * jsonb_ops GIN opclass support functions
 *
 */

Datum
gin_compare_jsonb(PG_FUNCTION_ARGS)
{
	text	   *arg1 = PG_GETARG_TEXT_PP(0);
	text	   *arg2 = PG_GETARG_TEXT_PP(1);
	int32		result;
	char	   *a1p,
			   *a2p;
	int			len1,
				len2;

	a1p = VARDATA_ANY(arg1);
	a2p = VARDATA_ANY(arg2);

	len1 = VARSIZE_ANY_EXHDR(arg1);
	len2 = VARSIZE_ANY_EXHDR(arg2);

	/* Compare text as bttextcmp does, but always using C collation */
	result = varstr_cmp(a1p, len1, a2p, len2, C_COLLATION_OID);

	PG_FREE_IF_COPY(arg1, 0);
	PG_FREE_IF_COPY(arg2, 1);

	PG_RETURN_INT32(result);
}

Datum
gin_extract_jsonb(PG_FUNCTION_ARGS)
{
	Jsonb	   *jb = (Jsonb *) PG_GETARG_JSONB(0);
	int32	   *nentries = (int32 *) PG_GETARG_POINTER(1);
	int			total = 2 * JB_ROOT_COUNT(jb);
	JsonbIterator *it;
	JsonbValue	v;
	int			i = 0,
				r;
	Datum	   *entries;

	/* If the root level is empty, we certainly have no keys */
	if (total == 0)
	{
		*nentries = 0;
		PG_RETURN_POINTER(NULL);
	}

	/* Otherwise, use 2 * root count as initial estimate of result size */
	entries = (Datum *) palloc(sizeof(Datum) * total);

	it = JsonbIteratorInit(&jb->root);

	while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
	{
		/* Since we recurse into the object, we might need more space */
		if (i >= total)
		{
			total *= 2;
			entries = (Datum *) repalloc(entries, sizeof(Datum) * total);
		}

		switch (r)
		{
			case WJB_KEY:
				entries[i++] = make_scalar_key(&v, true);
				break;
			case WJB_ELEM:
				/* Pretend string array elements are keys, see jsonb.h */
				entries[i++] = make_scalar_key(&v, (v.type == JsonbValue::jbvString));
				break;
			case WJB_VALUE:
				entries[i++] = make_scalar_key(&v, false);
				break;
			default:
				/* we can ignore structural items */
				break;
		}
	}

	*nentries = i;

	PG_RETURN_POINTER(entries);
}

Datum
gin_extract_jsonb_query(PG_FUNCTION_ARGS)
{
	int32	   *nentries = (int32 *) PG_GETARG_POINTER(1);
	StrategyNumber strategy = PG_GETARG_UINT16(2);
	int32	   *searchMode = (int32 *) PG_GETARG_POINTER(6);
	Datum	   *entries;

	if (strategy == JsonbContainsStrategyNumber)
	{
		/* Query is a jsonb, so just apply gin_extract_jsonb... */
		entries = (Datum *)
			DatumGetPointer(DirectFunctionCall2(gin_extract_jsonb,
												PG_GETARG_DATUM(0),
												PointerGetDatum(nentries)));
		/* ...although "contains {}" requires a full index scan */
		if (*nentries == 0)
			*searchMode = GIN_SEARCH_MODE_ALL;
	}
	else if (strategy == JsonbExistsStrategyNumber)
	{
		/* Query is a text string, which we treat as a key */
		text	   *query = PG_GETARG_TEXT_PP(0);

		*nentries = 1;
		entries = (Datum *) palloc(sizeof(Datum));
		entries[0] = make_text_key(JGINFLAG_KEY,
								   VARDATA_ANY(query),
								   VARSIZE_ANY_EXHDR(query));
	}
	else if (strategy == JsonbExistsAnyStrategyNumber ||
			 strategy == JsonbExistsAllStrategyNumber)
	{
		/* Query is a text array; each element is treated as a key */
		ArrayType  *query = PG_GETARG_ARRAYTYPE_P(0);
		Datum	   *key_datums;
		bool	   *key_nulls;
		int			key_count;
		int			i,
					j;

		deconstruct_array(query,
						  TEXTOID, -1, false, 'i',
						  &key_datums, &key_nulls, &key_count);

		entries = (Datum *) palloc(sizeof(Datum) * key_count);

		for (i = 0, j = 0; i < key_count; i++)
		{
			/* Nulls in the array are ignored */
			if (key_nulls[i])
				continue;
			entries[j++] = make_text_key(JGINFLAG_KEY,
										 VARDATA_ANY(key_datums[i]),
										 VARSIZE_ANY_EXHDR(key_datums[i]));
		}

		*nentries = j;
		/* ExistsAll with no keys should match everything */
		if (j == 0 && strategy == JsonbExistsAllStrategyNumber)
			*searchMode = GIN_SEARCH_MODE_ALL;
	}
	else
	{
		elog(ERROR, "unrecognized strategy number: %d", strategy);
		entries = NULL;			/* keep compiler quiet */
	}

	PG_RETURN_POINTER(entries);
}

Datum
gin_consistent_jsonb(PG_FUNCTION_ARGS)
{
	bool	   *check = (bool *) PG_GETARG_POINTER(0);
	StrategyNumber strategy = PG_GETARG_UINT16(1);

	/* Jsonb	   *query = PG_GETARG_JSONB(2); */
	int32		nkeys = PG_GETARG_INT32(3);

	/* Pointer	   *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
	bool	   *recheck = (bool *) PG_GETARG_POINTER(5);
	bool		res = true;
	int32		i;

	if (strategy == JsonbContainsStrategyNumber)
	{
		/*
		 * We must always recheck, since we can't tell from the index whether
		 * the positions of the matched items match the structure of the query
		 * object.  (Even if we could, we'd also have to worry about hashed
		 * keys and the index's failure to distinguish keys from string array
		 * elements.)  However, the tuple certainly doesn't match unless it
		 * contains all the query keys.
		 */
		*recheck = true;
		for (i = 0; i < nkeys; i++)
		{
			if (!check[i])
			{
				res = false;
				break;
			}
		}
	}
	else if (strategy == JsonbExistsStrategyNumber)
	{
		/*
		 * Although the key is certainly present in the index, we must recheck
		 * because (1) the key might be hashed, and (2) the index match might
		 * be for a key that's not at top level of the JSON object.  For (1),
		 * we could look at the query key to see if it's hashed and not
		 * recheck if not, but the index lacks enough info to tell about (2).
		 */
		*recheck = true;
		res = true;
	}
	else if (strategy == JsonbExistsAnyStrategyNumber)
	{
		/* As for plain exists, we must recheck */
		*recheck = true;
		res = true;
	}
	else if (strategy == JsonbExistsAllStrategyNumber)
	{
		/* As for plain exists, we must recheck */
		*recheck = true;
		/* ... but unless all the keys are present, we can say "false" */
		for (i = 0; i < nkeys; i++)
		{
			if (!check[i])
			{
				res = false;
				break;
			}
		}
	}
	else
		elog(ERROR, "unrecognized strategy number: %d", strategy);

	PG_RETURN_BOOL(res);
}

Datum
gin_triconsistent_jsonb(PG_FUNCTION_ARGS)
{
	GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
	StrategyNumber strategy = PG_GETARG_UINT16(1);

	/* Jsonb	   *query = PG_GETARG_JSONB(2); */
	int32		nkeys = PG_GETARG_INT32(3);

	/* Pointer	   *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
	GinTernaryValue res = GIN_MAYBE;
	int32		i;

	/*
	 * Note that we never return GIN_TRUE, only GIN_MAYBE or GIN_FALSE; this
	 * corresponds to always forcing recheck in the regular consistent
	 * function, for the reasons listed there.
	 */
	if (strategy == JsonbContainsStrategyNumber ||
		strategy == JsonbExistsAllStrategyNumber)
	{
		/* All extracted keys must be present */
		for (i = 0; i < nkeys; i++)
		{
			if (check[i] == GIN_FALSE)
			{
				res = GIN_FALSE;
				break;
			}
		}
	}
	else if (strategy == JsonbExistsStrategyNumber ||
			 strategy == JsonbExistsAnyStrategyNumber)
	{
		/* At least one extracted key must be present */
		res = GIN_FALSE;
		for (i = 0; i < nkeys; i++)
		{
			if (check[i] == GIN_TRUE ||
				check[i] == GIN_MAYBE)
			{
				res = GIN_MAYBE;
				break;
			}
		}
	}
	else
		elog(ERROR, "unrecognized strategy number: %d", strategy);

	PG_RETURN_GIN_TERNARY_VALUE(res);
}

/*
 *
 * jsonb_path_ops GIN opclass support functions
 *
 * In a jsonb_path_ops index, the GIN keys are uint32 hashes, one per JSON
 * value; but the JSON key(s) leading to each value are also included in its
 * hash computation.  This means we can only support containment queries,
 * but the index can distinguish, for example, {"foo": 42} from {"bar": 42}
 * since different hashes will be generated.
 *
 */

Datum
gin_extract_jsonb_path(PG_FUNCTION_ARGS)
{
	Jsonb	   *jb = PG_GETARG_JSONB(0);
	int32	   *nentries = (int32 *) PG_GETARG_POINTER(1);
	int			total = 2 * JB_ROOT_COUNT(jb);
	JsonbIterator *it;
	JsonbValue	v;
	PathHashStack tail;
	PathHashStack *stack;
	int			i = 0,
				r;
	Datum	   *entries;

	/* If the root level is empty, we certainly have no keys */
	if (total == 0)
	{
		*nentries = 0;
		PG_RETURN_POINTER(NULL);
	}

	/* Otherwise, use 2 * root count as initial estimate of result size */
	entries = (Datum *) palloc(sizeof(Datum) * total);

	/* We keep a stack of partial hashes corresponding to parent key levels */
	tail.parent = NULL;
	tail.hash = 0;
	stack = &tail;

	it = JsonbIteratorInit(&jb->root);

	while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
	{
		PathHashStack *parent;

		/* Since we recurse into the object, we might need more space */
		if (i >= total)
		{
			total *= 2;
			entries = (Datum *) repalloc(entries, sizeof(Datum) * total);
		}

		switch (r)
		{
			case WJB_BEGIN_ARRAY:
			case WJB_BEGIN_OBJECT:
				/* Push a stack level for this object */
				parent = stack;
				stack = (PathHashStack *) palloc(sizeof(PathHashStack));

				if (parent->parent)
				{
					/*
					 * We pass forward hashes from previous container nesting
					 * levels so that nested arrays with an outermost nested
					 * object will have element hashes mixed with the
					 * outermost key.  It's also somewhat useful to have
					 * nested objects' innermost values have hashes that are a
					 * function of not just their own key, but outer keys too.
					 *
					 * Nesting an array within another array will not alter
					 * innermost scalar element hash values, but that seems
					 * inconsequential.
					 */
					stack->hash = parent->hash;
				}
				else
				{
					/*
					 * At the outermost level, initialize hash with container
					 * type proxy value.  Note that this makes JB_FARRAY and
					 * JB_FOBJECT part of the on-disk representation, but they
					 * are that in the base jsonb object storage already.
					 */
					stack->hash = (r == WJB_BEGIN_ARRAY) ? JB_FARRAY : JB_FOBJECT;
				}
				stack->parent = parent;
				break;
			case WJB_KEY:
				/* initialize hash from parent */
				stack->hash = stack->parent->hash;
				/* and mix in this key */
				JsonbHashScalarValue(&v, &stack->hash);
				/* hash is now ready to incorporate the value */
				break;
			case WJB_ELEM:
				/* array elements use parent hash mixed with element's hash */
				stack->hash = stack->parent->hash;
				/* FALL THRU */
			case WJB_VALUE:
				/* mix the element or value's hash into the prepared hash */
				JsonbHashScalarValue(&v, &stack->hash);
				/* and emit an index entry */
				entries[i++] = UInt32GetDatum(stack->hash);
				/* Note: we assume we'll see KEY before another VALUE */
				break;
			case WJB_END_ARRAY:
			case WJB_END_OBJECT:
				/* Pop the stack */
				parent = stack->parent;
				pfree(stack);
				stack = parent;
				break;
			default:
				elog(ERROR, "invalid JsonbIteratorNext rc: %d", r);
		}
	}

	*nentries = i;

	PG_RETURN_POINTER(entries);
}

Datum
gin_extract_jsonb_query_path(PG_FUNCTION_ARGS)
{
	int32	   *nentries = (int32 *) PG_GETARG_POINTER(1);
	StrategyNumber strategy = PG_GETARG_UINT16(2);
	int32	   *searchMode = (int32 *) PG_GETARG_POINTER(6);
	Datum	   *entries;

	if (strategy != JsonbContainsStrategyNumber)
		elog(ERROR, "unrecognized strategy number: %d", strategy);

	/* Query is a jsonb, so just apply gin_extract_jsonb_path ... */
	entries = (Datum *)
		DatumGetPointer(DirectFunctionCall2(gin_extract_jsonb_path,
											PG_GETARG_DATUM(0),
											PointerGetDatum(nentries)));

	/* ... although "contains {}" requires a full index scan */
	if (*nentries == 0)
		*searchMode = GIN_SEARCH_MODE_ALL;

	PG_RETURN_POINTER(entries);
}

Datum
gin_consistent_jsonb_path(PG_FUNCTION_ARGS)
{
	bool	   *check = (bool *) PG_GETARG_POINTER(0);
	StrategyNumber strategy = PG_GETARG_UINT16(1);

	/* Jsonb	   *query = PG_GETARG_JSONB(2); */
	int32		nkeys = PG_GETARG_INT32(3);

	/* Pointer	   *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
	bool	   *recheck = (bool *) PG_GETARG_POINTER(5);
	bool		res = true;
	int32		i;

	if (strategy != JsonbContainsStrategyNumber)
		elog(ERROR, "unrecognized strategy number: %d", strategy);

	/*
	 * jsonb_path_ops is necessarily lossy, not only because of hash
	 * collisions but also because it doesn't preserve complete information
	 * about the structure of the JSON object.  Besides, there are some
	 * special rules around the containment of raw scalars in arrays that are
	 * not handled here.  So we must always recheck a match.  However, if not
	 * all of the keys are present, the tuple certainly doesn't match.
	 */
	*recheck = true;
	for (i = 0; i < nkeys; i++)
	{
		if (!check[i])
		{
			res = false;
			break;
		}
	}

	PG_RETURN_BOOL(res);
}

Datum
gin_triconsistent_jsonb_path(PG_FUNCTION_ARGS)
{
	GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
	StrategyNumber strategy = PG_GETARG_UINT16(1);

	/* Jsonb	   *query = PG_GETARG_JSONB(2); */
	int32		nkeys = PG_GETARG_INT32(3);

	/* Pointer	   *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
	GinTernaryValue res = GIN_MAYBE;
	int32		i;

	if (strategy != JsonbContainsStrategyNumber)
		elog(ERROR, "unrecognized strategy number: %d", strategy);

	/*
	 * Note that we never return GIN_TRUE, only GIN_MAYBE or GIN_FALSE; this
	 * corresponds to always forcing recheck in the regular consistent
	 * function, for the reasons listed there.
	 */
	for (i = 0; i < nkeys; i++)
	{
		if (check[i] == GIN_FALSE)
		{
			res = GIN_FALSE;
			break;
		}
	}

	PG_RETURN_GIN_TERNARY_VALUE(res);
}

/*
 * Construct a jsonb_ops GIN key from a flag byte and a textual representation
 * (which need not be null-terminated).  This function is responsible
 * for hashing overlength text representations; it will add the
 * JGINFLAG_HASHED bit to the flag value if it does that.
 */
static Datum
make_text_key(char flag, const char *str, int len)
{
	text	   *item;
	char		hashbuf[10];

	if (len > JGIN_MAXLENGTH)
	{
		uint32		hashval;

		hashval = DatumGetUInt32(hash_any((const unsigned char *) str, len));
		snprintf(hashbuf, sizeof(hashbuf), "%08x", hashval);
		str = hashbuf;
		len = 8;
		flag |= JGINFLAG_HASHED;
	}

	/*
	 * Now build the text Datum.  For simplicity we build a 4-byte-header
	 * varlena text Datum here, but we expect it will get converted to short
	 * header format when stored in the index.
	 */
	item = (text *) palloc(VARHDRSZ + len + 1);
	SET_VARSIZE(item, VARHDRSZ + len + 1);

	*VARDATA(item) = flag;

	memcpy(VARDATA(item) + 1, str, len);

	return PointerGetDatum(item);
}

/*
 * Create a textual representation of a JsonbValue that will serve as a GIN
 * key in a jsonb_ops index.  is_key is true if the JsonbValue is a key,
 * or if it is a string array element (since we pretend those are keys,
 * see jsonb.h).
 */
static Datum
make_scalar_key(const JsonbValue *scalarVal, bool is_key)
{
	Datum		item;
	char	   *cstr;

	switch (scalarVal->type)
	{
		case JsonbValue::jbvNull:
			Assert(!is_key);
			item = make_text_key(JGINFLAG_NULL, "", 0);
			break;
		case JsonbValue::jbvBool:
			Assert(!is_key);
			item = make_text_key(JGINFLAG_BOOL,
								 scalarVal->val.boolean ? "t" : "f", 1);
			break;
		case JsonbValue::jbvNumeric:
			Assert(!is_key);

			/*
			 * A normalized textual representation, free of trailing zeroes,
			 * is required so that numerically equal values will produce equal
			 * strings.
			 *
			 * It isn't ideal that numerics are stored in a relatively bulky
			 * textual format.  However, it's a notationally convenient way of
			 * storing a "union" type in the GIN B-Tree, and indexing Jsonb
			 * strings takes precedence.
			 */
			cstr = numeric_normalize(scalarVal->val.numeric);
			item = make_text_key(JGINFLAG_NUM, cstr, strlen(cstr));
			pfree(cstr);
			break;
		case JsonbValue::jbvString:
			item = make_text_key(is_key ? JGINFLAG_KEY : JGINFLAG_STR,
								 scalarVal->val.string.val,
								 scalarVal->val.string.len);
			break;
		default:
			elog(ERROR, "unrecognized jsonb scalar type: %d", scalarVal->type);
			item = 0;			/* keep compiler quiet */
			break;
	}

	return item;
}


text:
import unittest2

from aws_certificate_management.configure_dns import (
        normalize_domain, normalize_hosted_zone, get_dns_stack_name, DNS_STACK_NAME_POSTFIX,
        get_bucket_stack_name, BUCKET_STACK_NAME_POSTFIX,
        get_stack_action_handler)

class DNSTests(unittest2.TestCase):
    def test_get_dns_stack_name_removes_invalid_characters(self):
        stack_name = get_dns_stack_name("foo-bar.invalid")
        self.assertEqual(stack_name, "foo-barinvalid" + DNS_STACK_NAME_POSTFIX)

    def test_get_bucket_stack_name_removes_invalid_characters(self):
        stack_name = get_bucket_stack_name("foo-bar.invalid")
        self.assertEqual(stack_name, "foo-barinvalid" + BUCKET_STACK_NAME_POSTFIX)

    def test_normalize_domain_wildcard(self):
        self.assertEqual(normalize_domain("*.foo.bar"), "foo.bar")

    def test_normalize_domain_www(self):
        self.assertEqual(normalize_domain("www.foo.bar"), "foo.bar")

    def test_normalize_domain_no_wildcard(self):
        self.assertEqual(normalize_domain("foo.bar"), "foo.bar")

    def test_normalize_hosted_zone_wildcard(self):
        self.assertEqual(normalize_hosted_zone("*.foo.bar"), "foo.bar.")

    def test_normalize_hosted_zone_www(self):
        self.assertEqual(normalize_hosted_zone("www.foo.bar"), "foo.bar.")

    def test_normalize_hosted_zone_no_wildcard(self):
        self.assertEqual(normalize_hosted_zone("foo.bar"), "foo.bar.")

    def test_normalize_hosted_zone_no_dot(self):
        self.assertEqual(normalize_hosted_zone("foo.bar"), "foo.bar.")

    def test_get_stack_action_handler_no_tokens(self):
        handler = get_stack_action_handler('*.foo.invalid', '*.foo.invalid.')
        self.assertIsInstance(handler, object)

    def test_get_stack_action_handler_no_tokens_separate_hz(self):
        handler = get_stack_action_handler('*.foo.invalid', 'foo.invalid.')
        self.assertIsInstance(handler, object)

    def test_get_stack_action_handler_no_tokens_different_hz(self):
        handler = get_stack_action_handler('*.foo.bar.invalid', 'bar.invalid.')
        self.assertIsInstance(handler, object)

    def test_get_stack_action_handler_with_tokens(self):
        handler = get_stack_action_handler(
            '*.foo.invalid', 'foo.invalid.', 'verification_token', ['dkim1', 'dkim2', 'dkim3'])
        self.assertIsInstance(handler, object)


text:
#import <Foundation/Foundation.h>

@class DeezerOAuthView;

/**
 * Deezer OAuth delegate. Use into DeezerConnect class.
 * You don't have to implements this delegate, only DeezerConnect uses it.
 */
@protocol DeezerOAuthDelegate <NSObject>

@optional

/**
 * The connection OAuth succeeded.
 */
- (void)deezerOAuthSucceededWithToken:(NSString*)token expirationDate:(NSDate*)expirationDate;

/**
 * The connection OAuth not succeeded (example: when there is a wrong login/password).
 */
- (void)deezerOAuthDidNotSucceed:(BOOL)cancelled;

/**
 * The connection OAuth failed.
 */
- (void)deezerOAuth:(DeezerOAuthView*)deezerOAuth didFailWithError:(NSError *)error;

@end


text:
from Crypto.Random.random import StrongRandom, Random
from Crypto.Hash import HMAC, SHA512
from Crypto.Cipher import AES
from django.conf import settings

import logging
import base64
import string
import qrcode.image.svg

logger = logging.getLogger(__name__)

class QR2AuthCore(object):
    '''
    QR2Auth core implementation.
    This class provides the core functionality for the
    challenge response protocol.
    QR2Auth is a challenge response protocol with symmetric
    keys.

    TODO: Review required!
    '''
    def __init__(self, shared_secret=None, enc_key=None):
        '''
        Initialize QR2Auth core

        :param str shared_secret: The users shared secret.
        :param str enc_key: The passphrase to decrypt the shared secret.
        '''
        # TODO: make variables private!
        self.challenge = None
        self.start = None
        self.end = None
        if settings.Q2A_OTP_LENGTH in range(6, 11):
            self.otp_length = settings.Q2A_OTP_LENGTH
        else:
            self.otp_length = 8     # default: 8 digest OTP
        # encryption key for shared secret
        self.enc_key = enc_key
        self.shared_secret = shared_secret

    def set_shared_secret(self, shared_secret):
        '''
        Setter for shared secret

        :param str shared_secret: The users shared secret.
        :rtype: void
        '''
        self.shared_secret = shared_secret

    def set_challenge(self, challenge):
        '''
        Setter for the challenge

        :param str challenge: The QR2Auth challenge.
        :rtype: void
        '''
        self.challenge = challenge

    def get_challenge(self):
        '''
        Generate a QR2Auth challenge.
        A QR2Auth challenge consists of 128 random bits generated by PyCrypto
        with StrongRandom.
        These random bits are hashed with SHA512. This hash value represents
        the challenge.

        :return: A tuple containing the QR2Auth challenge as well as the range
                 of the OTP in the response hash value.
        :rtype: tuple
        '''
        random_pool = StrongRandom()
        nonce = random_pool.getrandbits(128)
        nonce_hash = SHA512.new(str(nonce)).hexdigest()
        self.start = int(random_pool.randint(0, 128))
        '''
        Start and end of the range must be between 0 and the length of the hash
        We use Sha512, so in this case start and end must be between
        0 and 128
        '''
        self.end = self.start + self.otp_length
        if self.end > len(nonce_hash):
            self.end = self.end - len(nonce_hash)
        self.challenge = nonce_hash
        return self.challenge, self.start, self.end

    def keygen(self):
        '''
        Generate the secret key for QR2Auth aka shared secret.
        A QR2Auth secret key consists of 256 random bits generated by PyCrypto
        with StrongRandom.
        The random bits are hashed with SHA512. This hash value
        represents the secret key aka. shared secret.

        :return: A QRtoAuth shared secret.
        :rtype: str
        '''
        random_pool = StrongRandom()
        key_seed = random_pool.getrandbits(256)
        key = SHA512.new(str(key_seed))
        self.shared_secret = key.hexdigest()
        return self.shared_secret

    def xor_key(self):
        '''
        Bitwise XOR the shared secret with the QR password.

        :return: A tuple containing the QR password and the XORed
                 shared secret.
        :rtype: tuple
        '''
        # The QR password has 4 digits and we need 128 digits for
        # XOR with the shared secret
        qrpassword = self.__pwgen()
        padded_pwd = qrpassword * 32
        '''
        convert strings to a list of character pair tuples
        go through each tuple, converting them to ASCII code (ord)
        perform exclusive or on the ASCII code
        then convert the result back to ASCII (chr)
        merge the resulting array of characters as a string
        '''
        xored = ''.join(chr(ord(a) ^ ord(b)) for a,  b in zip(padded_pwd,
                                                             self.shared_secret))
        return qrpassword, base64.encodestring(xored)

    def make_otp(self):
        '''
        Create a QR2Auth one-time password

        :raise NotImplementedError: The server will never create an OTP, so
                                    there is no point to implement that.
        '''
        raise NotImplementedError

    def verify_response(self, received_otp, start, end):
        '''
        Verify the One time password (OTP) aka response.
        A QR2Auth Response consists of 8 digests of the HMAC-SHA512 value
        from the challenge with the shared_secret used as key for the HMAC.

        :param str received_otp: The submitted one time password from the
                                 client.
        :param str start: Start of the OTP range
        :param str end: End of the OTP range
        :return: True if the OTP is valid otherwise False
        :rtype: bool
        '''
        # decrypt shared secret
        aes = AESCipher(self.enc_key)
        _shared_secret = aes.decrypt(self.shared_secret.__str__())
        otp_hash = HMAC.new(_shared_secret,
                            self.challenge.__str__(), SHA512)

        # convert the received otp range from string to int
        start = int(start)
        end = int(end)

        # do some logging
        logger.debug('CORE Using shared secret: %s' % _shared_secret)
        logger.debug('CORE Using challenge: %s' % self.challenge)
        logger.debug('CORE HMAC is: %s' % otp_hash.hexdigest())
        logger.debug('CORE OTP range is: (%i, %i)' % (start, end))

        if end < start:
            otp = otp_hash.hexdigest()[start:]
            otp += otp_hash.hexdigest()[:end]
        else:
            otp = otp_hash.hexdigest()[start:end]

        # and log the OTPs
        logger.debug('CORE Received OTP: %s' % received_otp)
        logger.debug('CORE Computed OTP: %s' % otp)

        if otp == received_otp:
            return True
        return False

    def qrgen(self, is_key=False, key=''):
        '''
        Generate an SVG image containing the QR code

        :param bool is_key: True if a shared secret QR code
                            is created otherwise False
        :param str key: The user's shared secret
        :return: An image object containing the SVG image
        :rtype: Object
        '''
        qrfactory = qrcode.image.svg.SvgImage
        # generate the QR code
        if is_key is True:
            '''
            Add a prefix so that another application can distinguish the key
            from the challenge.
            '''
            qr_content = '{key}'
            qr_content += key
            # test vectors
            key_hmac = HMAC.new(self.shared_secret, self.shared_secret, SHA512)
            qr_content += ','
            qr_content += key_hmac.hexdigest()
            # make the QR code
            qrimg = qrcode.make(qr_content,
                                image_factory=qrfactory)
        else:
            qrimg = qrcode.make('{' + str(self.start) + ',' +
                                str(self.end) + '}' +
                                self.challenge, image_factory=qrfactory)
        return qrimg

    #
    # Internals
    #
    def __pwgen(self, size=4, chars=string.digits+string.ascii_lowercase):
        '''
        Generate a password. This password is used as the QR password
        for the bitwise XOR of the shared secret.

        :param str size:  The length of the password
        :param str chars: The characters the password should contain.
                          In this case we want digits and ASCII lowercase
                          letters.
        :return: A generated QR password
        :rtype: string
        '''
        return ''.join(Random.random.choice(chars) for _ in range(size))

class AESCipher(object):
    '''
    AES cipher for QR2Auth. AES is used to store the users shared_secret
    encrypted in the database.

    TODO: Review required!
    '''
    def __init__(self, passphrase):
        '''
        Initialize AESCipher

        :param str passphrase: The passphrase to generate an AES key.
        '''
        self.passphrase = passphrase
        self.mode = AES.MODE_CBC
        self.iv = None
        self.block_size = 32
        self.padding = '@'
        # use the Sha512 hash of the passphrase as AES key
        # TODO: Check if this key generation is strong enough
        self.key = SHA512.new(self.passphrase).digest()[:self.block_size]

    def encrypt(self, plaintext):
        '''
        Encrypt a string with AES

        :param str plaintext: The text to encrypt
        :return: Returns the base64 encoded initialization vector + cipher text
                         of the given plaintext.
        :rtype: str
        '''
        # Initialization vector must be 16 bytes long
        self.iv = Random.new().read(self.block_size)[:16]
        aes = AES.new(self.key, self.mode, self.iv)
        return base64.b64encode(self.iv + aes.encrypt(self._pad(plaintext)))

    def decrypt(self, ciphertext):
        '''
        Decrypt a string encrypted with AES

        :param str ciphertext: The base64 encoded initialization vector +
                               cipher text.
        :return: Returns the plaintext of the given cipher text.
        :rtype: str
        '''
        self.iv = base64.b64decode(ciphertext)[:16]
        ciphertext = base64.b64decode(ciphertext)[16:]
        aes = AES.new(self.key, AES.MODE_CBC, self.iv)
        return aes.decrypt(ciphertext).rstrip(self.padding)

    #
    # Internals
    #
    def _pad(self, s):
        '''
        Pad the text before encryption, because the length of the text must
        be a multiple of the block size.

        :param str s: The string to add a padding.
        :return: Returns the given string + padding.
        :rtype: str
        '''
        return s + (self.block_size - len(s) % self.block_size) * self.padding


text:
extern inline Sclr
sclr(double input);

extern inline void
Sclr_NEW(Eina_Inarray **key);

extern inline void
Sclr_FREE(Eina_Inarray **key);

extern inline void
Sclr_PUSH(Eina_Inarray **key, Sclr *input);

extern inline void
Sclr_POP(Eina_Inarray **key);

extern inline void
Sclr_READ(Eina_Inarray **key, Sclr *bufferkey, uint64_t index);

extern inline void
Sclr_WRITE(Eina_Inarray **key, Sclr *bufferkey, uint64_t index);

#undef SUBTYPES
#undef TYPE


text:
package me.gong.lavarun.plugin.game.events;

import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;

public class BlockRemovedEvent extends Event {

    private static final HandlerList handlers = new HandlerList();

    private Block block;
    private Player whom;
    private boolean manual;

    public BlockRemovedEvent(Block block, Player whom, boolean manual) {
        this.block = block;
        this.whom = whom;
        this.manual = manual;
    }

    public Block getBlock() {
        return block;
    }

    public Player getWhom() {
        return whom;
    }

    public boolean isManual() {
        return manual;
    }

    @Override
    public HandlerList getHandlers() {
        return handlers;
    }

    public static HandlerList getHandlerList() {
        return handlers;
    }
}


text:
from model.new_contact import New_contact
import re

class ContactHelper:

    def __init__(self, app):
        self.app = app

    def fill_new_contact_form(self, new_contact):
        wd = self.app.wd
        self.open_add_new_contact()
        self.fill_contact_form(new_contact)
        # submit the form
        wd.find_element_by_name("submit").click()
        self.contact_list_cache = None

    def fill_contact_form(self, contact):
        wd = self.app.wd
        self.change_field_value("firstname", contact.name)
        self.change_field_value("lastname", contact.last_name)
        self.change_field_value("home", contact.home_number)
        self.change_field_value("address", contact.address)
        self.change_field_value("mobile", contact.mobile_number)
        self.change_field_value("work", contact.work_number)
        self.change_field_value("phone2", contact.secondary_number)
        self.change_field_value("email", contact.email)
        self.change_field_value("email2", contact.email2)
        self.change_field_value("email3", contact.email3)

    def change_field_value(self, field_name, text):
        wd = self.app.wd
        if text is not None:
            wd.find_element_by_name(field_name).click()
            wd.find_element_by_name(field_name).clear()
            wd.find_element_by_name(field_name).send_keys(text)

    def open_add_new_contact(self):
        wd = self.app.wd
        wd.find_element_by_link_text("add new").click()

    contact_list_cache = None

    def get_contact_list(self):
        if self.contact_list_cache is None:
            wd = self.app.wd
            self.open_home_page()
            self.contact_list_cache = []
            for row in wd.find_elements_by_name("entry"):
                cells = row.find_elements_by_tag_name("td")
                firstname = cells[2].text
                lastname = cells[1].text
                address = cells[3].text
                all_emails = cells[4].text
                id = cells[0].find_element_by_tag_name("input").get_attribute("value")
                all_phones = cells[5].text
 #               print(all_phones)
                self.contact_list_cache.append(New_contact(name=firstname, last_name=lastname, id=id, address=address,
                                                           all_phones_from_home_page=all_phones,
                                                           all_emails_from_home_page=all_emails))
        return list(self.contact_list_cache)

    def open_home_page(self):
        wd = self.app.wd
        if not(wd.current_url.endswith("/group.php") and len(wd.find_elements_by_name("new")) > 0):
            wd.find_element_by_link_text("groups").click()
        wd.find_element_by_link_text("home").click()

    def count(self):
        wd = self.app.wd
        self.open_home_page()
        return len(wd.find_elements_by_name("selected[]"))

    def del_first_contact(self):
        self.del_contact_by_index(0)

    def del_contact_by_index(self, index):
        wd = self.app.wd
        self.open_home_page()
        self.select_contact_by_index(index)
        # submit deletion
        wd.find_elements_by_class_name("left")[1].click()
        wd.switch_to_alert().accept()
        self.contact_list_cache = None

    def select_first_contact(self):
        wd = self.app.wd
        wd.find_element_by_name("selected[]").click()

    def select_contact_by_index(self, index):
        wd = self.app.wd
        wd.find_elements_by_name("selected[]")[index].click()

    def modify_first_contact_name(self, new_name_data):
        self.modify_some_contact_name(0, new_name_data )

    def modify_some_contact_name(self, index, new_name_data):
        wd = self.app.wd
        self.open_contact_to_edit_by_index(index)
        # enter new data
        self.fill_contact_form(new_name_data)
        # sumbit modification form
        wd.find_element_by_name("update").click()
        self.contact_list_cache = None

    def open_contact_to_edit_by_index(self, index):
        wd = self.app.wd
        self.open_home_page()
        # open contact to modify
        row = wd.find_elements_by_name("entry")[index]
        cell = row.find_elements_by_tag_name("td")[7]
        cell.find_element_by_tag_name("a").click()

    def open_contact_to_view_by_index(self, index):
        wd = self.app.wd
        self.open_home_page()
        # open contact to modify
        row = wd.find_elements_by_name("entry")[index]
        cell = row.find_elements_by_tag_name("td")[6]
        cell.find_element_by_tag_name("a").click()

    def get_contact_info_from_edit_page(self, index):
        wd = self.app.wd
        self.open_contact_to_edit_by_index(index)
        name = wd.find_element_by_name("firstname").get_attribute("value")
        last_name = wd.find_element_by_name("lastname").get_attribute("value")
        id = wd.find_element_by_name("id").get_attribute("value")
        home_number = wd.find_element_by_name("home").get_attribute("value")
        work_number = wd.find_element_by_name("work").get_attribute("value")
        mobile_number = wd.find_element_by_name("mobile").get_attribute("value")
        address = wd.find_element_by_name("address").text
        email = wd.find_element_by_name("email").get_attribute("value")
        email2 = wd.find_element_by_name("email2").get_attribute("value")
        email3 = wd.find_element_by_name("email3").get_attribute("value")
        secondary_number = wd.find_element_by_name("phone2").get_attribute("value")
        return New_contact(name = name, last_name = last_name, id = id, home_number = home_number, work_number = work_number,
                           mobile_number = mobile_number, secondary_number = secondary_number, address = address,
                           email=email, email2=email2, email3=email3)

    def get_contact_from_view_page(self, index):
        wd = self.app.wd
        self.open_contact_to_view_by_index(index)
        text = wd.find_element_by_id("content").text
        home_number = re.search("H: (.*)", text).group(1)
        mobile_number = re.search("M: (.*)", text).group(1)
        work_number = re.search("W: (.*)", text).group(1)
        secondary_number = re.search("P: (.*)", text).group(1)
        return New_contact(home_number=home_number, work_number=work_number,
                           mobile_number=mobile_number, secondary_number=secondary_number)

    def del_contact_by_id(self, id):
        wd = self.app.wd
        self.open_home_page()
        self.select_contact_by_id(id)
        # submit deletion
        wd.find_elements_by_class_name("left")[1].click()
        wd.switch_to_alert().accept()
        self.contact_list_cache = None

    def select_contact_by_id(self, id):
        wd = self.app.wd
        wd.find_element_by_css_selector("input[id='%s']" % id).click()