text:
package com.github.fengtan.sophie.composites;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.NoOpResponseParser;
import org.apache.solr.client.solrj.impl.HttpSolrClient.RemoteSolrException;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.FacetField.Count;
import org.apache.solr.client.solrj.response.LukeResponse.FieldInfo;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.luke.FieldFlag;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.NamedList;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

import com.github.fengtan.sophie.Sophie;
import com.github.fengtan.sophie.beans.Config;
import com.github.fengtan.sophie.beans.SolrUtils;
import com.github.fengtan.sophie.beans.SophieException;
import com.github.fengtan.sophie.dialogs.EditDateValueDialog;
import com.github.fengtan.sophie.dialogs.EditListValueDialog;
import com.github.fengtan.sophie.dialogs.EditTextValueDialog;
import com.github.fengtan.sophie.dialogs.EditValueDialog;
import com.github.fengtan.sophie.dialogs.ExceptionDialog;
import com.github.fengtan.sophie.toolbars.ChangeListener;

/**
 * Table listing Solr documents.
 */
public class DocumentsTable {

    /**
     * Yellow - color of modified documents.
     */
    private static final Color YELLOW = Display.getCurrent().getSystemColor(SWT.COLOR_YELLOW);

    /**
     * Red - color of deleted documents.
     */
    private static final Color RED = Display.getCurrent().getSystemColor(SWT.COLOR_RED);

    /**
     * Green - color of added documents.
     */
    private static final Color GREEN = Display.getCurrent().getSystemColor(SWT.COLOR_GREEN);

    /**
     * Label displayed in lieu of the value when the field is not stored.
     */
    private static final String LABEL_NOT_STORED = "(not stored)";

    /**
     * Label displayed then the document has no value for a specific field.
     */
    private static final String LABEL_EMPTY = "(empty)";

    /**
     * Page size - how many documents do we fetch from Solr at a time.
     */
    private static final int PAGE_SIZE = Config.getDocumentsPageSize();

    /**
     * Facet limit - how many facets values do we display at most in each
     * filter.
     */
    private static final int FACET_LIMIT = Config.getDocumentsFacetsLimit();

    /**
     * Boost assigned to new field values.
     */
    private static final float BOOST = 1.0f;

    /**
     * Cached documents fetched from the server, keyed by page ID.
     */
    private Map<Integer, SolrDocumentList> pages;

    /**
     * Current active filters (filter values keyed by filter name).
     */
    private Map<String, String> filters = new HashMap<String, String>();

    /**
     * Unique key field name.
     */
    private String uniqueField;

    /**
     * Name of the column currently sorted.
     */
    private String sortField;

    /**
     * Whether the table is currently sorted in ascending or descending order.
     */
    private ORDER sortOrder = ORDER.asc;

    /**
     * List of documents locally updated.
     */
    private List<SolrDocument> documentsUpdated;

    /**
     * List of documents locally deleted.
     */
    private List<SolrDocument> documentsDeleted;

    /**
     * List of documents locally added.
     */
    private List<SolrDocument> documentsAdded;

    /**
     * Change listener - allows the 'Upload' button to detect whether there are
     * local changes to send to Solr.
     */
    private ChangeListener changeListener;

    /**
     * Table.
     */
    private Table table;

    /**
     * Table editor.
     */
    private TableEditor editor;

    /**
     * Parent composite.
     */
    private Composite composite;

    /**
     * Create a new table listing Solr documents.
     *
     * @param composite
     *            Parent composite.
     * @param selectionListener
     *            Selection listener - allows certain buttons to be enabled only
     *            when a document is selected.
     * @param changeListener
     *            Change listener - allows the 'Upload' button to detect whether
     *            there are local changes to send to Solr.
     * @throws SophieException
     *             If the table could not be created.
     */
    public DocumentsTable(Composite composite, SelectionListener selectionListener, ChangeListener changeListener) throws SophieException {
        // Initialize unique key and sort field.
        // Rows always need to be sorted so locally updated documents do not end
        // up at the end of the list after the user upload them. We sort by
        // unique field by default.
        uniqueField = SolrUtils.getRemoteUniqueField();
        sortField = uniqueField;

        // Instantiate table.
        this.composite = composite;
        createTable();
        this.editor = new TableEditor(table);
        this.changeListener = changeListener;
        table.addSelectionListener(selectionListener);

        // Add first column (row #).
        TableColumn columnNumber = new TableColumn(table, SWT.LEFT);
        columnNumber.setText("#");
        columnNumber.pack();

        // Get facet values.
        List<FieldInfo> fields = SolrUtils.getRemoteFields();
        Map<String, FacetField> facets;
        try {
            facets = getRemoteFacets(fields);
        } catch (SophieException e) {
            Sophie.log.warn("Unable to refresh filters", e);
            facets = Collections.emptyMap();
        }

        // Sort fields by field names.
        Collections.sort(fields, new Comparator<FieldInfo>() {
            @Override
            public int compare(FieldInfo field1, FieldInfo field2) {
                String name1 = (field1 == null) ? StringUtils.EMPTY : field1.getName();
                String name2 = (field2 == null) ? StringUtils.EMPTY : field2.getName();
                return name1.compareTo(name2);
            }
        });

        // Add subsequent columns (fields).
        for (int i = 0; i < fields.size(); i++) {
            FieldInfo field = fields.get(i);
            FacetField facet = facets.get(field.getName());
            addField(field, facet, i + 1); // First row is used for row #.
        }

        // Initialize cache + row count.
        refresh();
    }

    /**
     * Create the Table.
     */
    private void createTable() {
        // Instantiate the table.
        int style = SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.HIDE_SELECTION | SWT.VIRTUAL;
        table = new Table(composite, style);

        // Set layout.
        GridData gridData = new GridData(GridData.FILL_BOTH);
        gridData.grabExcessVerticalSpace = true;
        table.setLayoutData(gridData);

        // Set styles.
        table.setLinesVisible(true);
        table.setHeaderVisible(true);

        // Add KeyListener to delete documents.
        table.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent event) {
                if (event.keyCode == SWT.DEL) {
                    deleteSelectedDocument();
                }
            }
        });

        // Initialize item count to 1 so we can populate the first row with
        // filters.
        table.setItemCount(1);

        // Populate subsequent rows with remote documents (virtual table).
        table.addListener(SWT.SetData, new Listener() {
            @Override
            public void handleEvent(Event event) {
                TableItem item = (TableItem) event.item;
                int rowIndex = table.indexOf(item);

                // The first line is populated by filters.
                if (rowIndex == 0) {
                    return;
                }

                SolrDocument document;
                // The last lines are populated by local additions.
                if (rowIndex >= table.getItemCount() - documentsAdded.size()) {
                    document = documentsAdded.get(documentsAdded.size() - table.getItemCount() + rowIndex);
                    item.setBackground(GREEN);
                } else {
                    try {
                        // rowIndex - 1 since the first line is used for
                        // filters.
                        document = getRemoteDocument(rowIndex - 1);
                    } catch (SophieException e) {
                        ExceptionDialog.open(composite.getShell(), new SophieException("Unable to populate table", e));
                        return;
                    }
                }

                // First column is used to show the row ID.
                item.setText(0, Integer.toString(rowIndex));

                // Subsequent columns are used to show field values.
                for (int index = 1; index < table.getColumnCount(); index++) {
                    TableColumn column = table.getColumn(index);
                    String fieldName = (String) column.getData("fieldName");
                    FieldInfo field = (FieldInfo) column.getData("field");
                    // If field is not stored, display message.
                    if (!SolrUtils.getFlags(field).contains(FieldFlag.STORED)) {
                        item.setText(index, LABEL_NOT_STORED);
                    } else {
                        Object value = document.getFieldValue(fieldName);
                        item.setText(index, value == null ? StringUtils.EMPTY : value.toString());
                    }
                }

                // Store document in item.
                item.setData("document", document);
            }
        });

        // Add doubleclick listener to edit values.
        table.addListener(SWT.MouseDoubleClick, new Listener() {
            public void handleEvent(Event event) {
                Point point = new Point(event.x, event.y);
                TableItem item = table.getItem(point);
                if (item == null) {
                    return;
                }
                // The first row is used for filters.
                if (table.indexOf(item) == 0) {
                    return;
                }
                // We add 1 since the first column is used for row ID's.
                for (int i = 1; i < table.getColumnCount(); i++) {
                    Rectangle rect = item.getBounds(i);
                    if (rect.contains(point)) {
                        SolrDocument document = (SolrDocument) item.getData("document");
                        String fieldName = (String) table.getColumn(i).getData("fieldName");
                        FieldInfo field = (FieldInfo) table.getColumn(i).getData("field");
                        Object defaultValue = document.getFieldValue(fieldName);
                        // Add editor dialog:
                        // - list widget if we are dealing with a multi-valued
                        // field.
                        // - datepicker if we field type contains "date".
                        // - text if we are dealing with any other field type.
                        EditValueDialog dialog;
                        if (SolrUtils.getFlags(field).contains(FieldFlag.MULTI_VALUED)) {
                            dialog = new EditListValueDialog(composite.getShell(), (AbstractList<?>) defaultValue);
                        } else if (StringUtils.containsIgnoreCase(field.getType(), "date")) {
                            dialog = new EditDateValueDialog(composite.getShell(), (Date) defaultValue);
                        } else {
                            String oldValueString = Objects.toString(defaultValue, StringUtils.EMPTY);
                            dialog = new EditTextValueDialog(composite.getShell(), oldValueString);
                        }
                        dialog.open();
                        if (dialog.getReturnCode() != IDialogConstants.OK_ID) {
                            return;
                        }
                        Object value = dialog.getValue();
                        if (!Objects.equals(defaultValue, value)) {
                            updateDocument(item, i, value);
                        }
                    }
                }
            }
        });
    }

    /**
     * Get field names.
     *
     * @return List of field names.
     */
    public List<String> getFieldNames() {
        List<String> fieldNames = new ArrayList<String>();
        for (int i = 0; i < table.getColumnCount(); i++) {
            String fieldName = (String) table.getColumn(i).getData("fieldName");
            // Field name is empty in the first column (row #).
            if (StringUtils.isNotEmpty(fieldName)) {
                fieldNames.add(fieldName);
            }
        }
        return fieldNames;
    }

    /**
     * Add (if value is not empty) or remove (if value is empty) a filter.
     *
     * @param fieldName
     *            Field name.
     * @param value
     *            Filter value.
     */
    private void updateFilters(String fieldName, String value) {
        if (StringUtils.isEmpty(value)) {
            filters.remove(fieldName);
        } else {
            filters.put(fieldName, value);
        }
    }

    /**
     * Get how many documents are in the remote index.
     *
     * @return How many documents are in the remote index.
     * @throws SophieException
     *             If the number of documents could not be determined.
     */
    private int getRemoteCount() throws SophieException {
        SolrQuery query = getBaseQuery(0, 0);
        try {
            // Solr returns a long, table expects an int.
            long count = Sophie.client.query(query).getResults().getNumFound();
            return Integer.parseInt(String.valueOf(count));
        } catch (SolrServerException | IOException | SolrException e) {
            throw new SophieException("Unable to count remote documents", e);
        }
    }

    /**
     * Get a list of remote facets keyed by field name.
     *
     * @param fields
     *            Fields.
     * @return List of facets keyed by field name.
     * @throws SophieException
     *             If facets could not be fetched.
     */
    private Map<String, FacetField> getRemoteFacets(List<FieldInfo> fields) throws SophieException {
        // Prepare query.
        SolrQuery query = getBaseQuery(0, 0);
        query.setFacet(true);
        query.setFacetSort("index");
        query.setFacetLimit(FACET_LIMIT);
        query.setFacetMissing(true);

        // For each field, determine whether Solr can generate a facet (fq works
        // only on indexed fields). If yes, then list that field in the query.
        for (FieldInfo field : fields) {
            if (SolrUtils.getFlags(field).contains(FieldFlag.INDEXED)) {
                query.addFacetField(field.getName());
            }
        }

        // Send query.
        Map<String, FacetField> facets = new HashMap<String, FacetField>();
        try {
            for (FacetField facet : Sophie.client.query(query).getFacetFields()) {
                facets.put(facet.getName(), facet);
            }
        } catch (SolrServerException | IOException | SolrException e) {
            throw new SophieException("Unable to fetch remote facets", e);
        }

        // Return facets keyed by field name.
        return facets;
    }

    /**
     * Get document to display at a specific row index. The document is
     * retrieved from the cache. If it is not in the cache, then we fetch a new
     * page of results and we populate the cache.
     *
     * @param rowIndex
     *            Row index.
     * @return Solr document.
     * @throws SophieException
     *             If the document could not be fetched from Solr.
     */
    private SolrDocument getRemoteDocument(int rowIndex) throws SophieException {
        // Compute page ID.
        int page = rowIndex / PAGE_SIZE;

        // If page is not in the cache, then fetch it from Solr and populate the
        // cache.
        if (!pages.containsKey(page)) {
            SolrQuery query = getBaseQuery(page * PAGE_SIZE, PAGE_SIZE);
            query.setSort(sortField, sortOrder);
            try {
                pages.put(page, Sophie.client.query(query).getResults());
            } catch (SolrServerException | IOException | SolrException e) {
                throw new SophieException("Unable to fetch remote document " + rowIndex, e);
            }
        }

        // Return Solr document from the cache.
        return pages.get(page).get(rowIndex % PAGE_SIZE);
    }

    /**
     * Get select query and populate the start/rows/fq parameters.
     *
     * @param start
     *            Offset at which Solr should being returning documents.
     * @param rows
     *            How many rows Solr should return.
     * @return Solr query.
     */
    private SolrQuery getBaseQuery(int start, int rows) {
        SolrQuery query = new SolrQuery("*:*");
        query.setStart(start);
        query.setRows(rows);
        // Add filters.
        for (Entry<String, String> filter : filters.entrySet()) {
            if (StringUtils.equals(filter.getValue(), LABEL_EMPTY)) {
                // Empty value needs a special syntax.
                query.addFilterQuery("-" + filter.getKey() + ":[* TO *]");
            } else {
                // Colons in value need to be escaped to avoid a syntax error.
                query.addFilterQuery(filter.getKey() + ":" + filter.getValue().replace(":", "\\:"));
            }
        }
        return query;
    }

    /**
     * Get the currently selected document.
     *
     * @return Currently selected document, or null if not row is selected.
     */
    public SolrDocument getSelectedDocument() {
        TableItem[] items = table.getSelection();
        if (items.length == 0) {
            return null;
        }
        return (SolrDocument) items[0].getData("document");
    }

    /**
     * Clear table and flush internal cache. This causes the table to be
     * re-populated with remote documents.
     *
     * @throws SophieException
     *             If the documents could not be fetched from Solr.
     */
    public void refresh() throws SophieException {
        // Flush cache.
        documentsUpdated = new ArrayList<SolrDocument>();
        documentsDeleted = new ArrayList<SolrDocument>();
        documentsAdded = new ArrayList<SolrDocument>();
        pages = new HashMap<Integer, SolrDocumentList>();
        changeListener.unchanged();

        // Clear table.
        try {
            // First row is for filters, the rest is for documents (remote +
            // locally added - though no local addition since we have just
            // refreshed documents).
            table.setItemCount(1 + getRemoteCount());
            table.clearAll();
        } catch (SophieException e) {
            table.setItemCount(1);
            table.clearAll();
            throw new SophieException("Unable to refresh documents from Solr server", e);
        }
    }

    /**
     * Export documents into CSV file.
     *
     * @throws SophieException
     *             If the documents could not be exported into a CSV file.
     */
    public void export() throws SophieException {
        // Open dialog to let the user select where the file will be dumped.
        FileDialog dialog = new FileDialog(table.getShell(), SWT.SAVE);
        dialog.setFilterNames(new String[] { "CSV Files (*.csv)", "All Files (*.*)" });
        dialog.setFilterExtensions(new String[] { "*.csv", "*.*" });
        String date = new SimpleDateFormat("yyyy-MM-dd-HH:mm").format(new Date());
        dialog.setFileName("documents_" + date + ".csv");
        String path = dialog.open();

        // User did not selected any location.
        if (path == null) {
            return;
        }

        // Open file for writing.
        Writer writer = null;
        try {
            writer = new PrintWriter(path, "UTF-8");
        } catch (FileNotFoundException | UnsupportedEncodingException e) {
            IOUtils.closeQuietly(writer);
            throw new SophieException("Unable to open file for writing: " + path, e);
        }

        // We buffer rows using pages to avoid filling up the RAM.
        for (int page = 0; page <= table.getItemCount() / PAGE_SIZE; page++) {
            // Get page from Solr.
            SolrQuery query = getBaseQuery(page * PAGE_SIZE, PAGE_SIZE);
            QueryRequest request = new QueryRequest(query);
            request.setResponseParser(new NoOpResponseParser("csv"));
            NamedList<Object> response;
            try {
                response = Sophie.client.request(request);
            } catch (SolrServerException | IOException | RemoteSolrException e) {
                IOUtils.closeQuietly(writer);
                throw new SophieException("Unable to get CSV documents from Solr", e);
            }

            // Write page into file.
            String csv = (String) response.get("response");
            try {
                IOUtils.write(csv, writer);
            } catch (IOException e) {
                IOUtils.closeQuietly(writer);
                throw new SophieException("Unable to write into file " + path, e);
            }
        }

        // Close file.
        try {
            writer.close();
        } catch (IOException e) {
            throw new SophieException("Unable to close file " + path, e);
        }
    }

    /**
     * Upload local changes to the Solr server.
     *
     * @throws SophieException
     *             If the local changes could not be uploaded to the Solr
     *             server.
     */
    public void upload() throws SophieException {
        // Upload local updates.
        for (SolrDocument document : documentsUpdated) {
            SolrInputDocument input = new SolrInputDocument();
            for (String name : document.getFieldNames()) {
                input.addField(name, document.getFieldValue(name), 1.0f);
            }
            try {
                // Returned object seems to have no relevant information.
                Sophie.client.add(input);
            } catch (SolrServerException | IOException | SolrException e) {
                throw new SophieException("Unable to update document in index: " + input.toString(), e);
            }
        }
        // Upload local deletions.
        for (SolrDocument document : documentsDeleted) {
            String id = Objects.toString(document.getFieldValue(uniqueField), StringUtils.EMPTY);
            try {
                Sophie.client.deleteById(id);
            } catch (SolrServerException | IOException | SolrException e) {
                throw new SophieException("Unable to delete document from index: " + id, e);
            }
        }
        // Upload local additions.
        for (SolrDocument document : documentsAdded) {
            SolrInputDocument input = new SolrInputDocument();
            for (String name : document.getFieldNames()) {
                input.addField(name, document.getFieldValue(name), BOOST);
            }
            try {
                // Returned object seems to have no relevant information.
                Sophie.client.add(input);
            } catch (SolrServerException | IOException | SolrException e) {
                throw new SophieException("Unable to add document to index: " + input.toString(), e);
            }
        }
        // Commit the index.
        try {
            Sophie.client.commit();
        } catch (SolrServerException | IOException | SolrException e) {
            throw new SophieException("Unable to commit index", e);
        }

        // Refresh so user can see the new state of the server.
        refresh();
    }

    /**
     * Restore index from a backup
     *
     * @param backupName
     *            Backup file name.
     * @throws SophieException
     *             If the backup could not be restored.
     */
    public void restore(String backupName) throws SophieException {
        ModifiableSolrParams params = new ModifiableSolrParams();
        params.set("command", "restore");
        params.set("name", backupName);
        QueryRequest request = new QueryRequest(params);
        request.setPath("/replication");
        try {
            Sophie.client.request(request);
            refresh();
        } catch (SolrServerException | IOException | SolrException e) {
            throw new SophieException("Unable to restore backup \"" + backupName + "\"", e);
        }
        refresh();
    }

    /**
     * Update a document locally.
     *
     * @param item
     *            Row containing the document to update.
     * @param columnIndex
     *            Column index of the field to update.
     * @param newValue
     *            New value.
     */
    private void updateDocument(TableItem item, int columnIndex, Object newValue) {
        SolrDocument document = (SolrDocument) item.getData("document");
        // The row may not contain any document (e.g. the first row, which
        // contains the filters).
        if (document == null) {
            return;
        }

        String fieldName = (String) table.getColumn(columnIndex).getData("fieldName");
        // We reduce by 1 since the first column is used for row ID.
        document.setField(fieldName, newValue);
        item.setText(columnIndex, Objects.toString(newValue, StringUtils.EMPTY));
        changeListener.changed();

        // If document was locally added, then leave it in documentsAdded and
        // return so it remains green.
        if (documentsAdded.contains(document)) {
            return;
        }

        // If document was locally deleted, then remove it from documentsDeleted
        // and let it go into documentsUpdated.
        if (documentsDeleted.contains(document)) {
            documentsDeleted.remove(document);
        }

        // Add document to documentsUpdated if it is not already there.
        if (!documentsUpdated.contains(document)) {
            documentsUpdated.add(document);
        }
        item.setBackground(YELLOW);
    }

    /**
     * Delete the selected document locally.
     *
     * @param item
     *            Row containing the document to delete.
     */
    public void deleteSelectedDocument() {
        SolrDocument document = getSelectedDocument();
        // The row may not contain any document (e.g. the first row, which
        // contains the filters).
        if (document == null) {
            return;
        }

        // If document is already deleted locally, then do nothing.
        if (documentsDeleted.contains(document)) {
            return;
        }

        int rowIndex = table.getSelectionIndex();
        // If document was locally added, then just remove it from local
        // additions.
        if (documentsAdded.contains(document)) {
            documentsAdded.remove(document);
            table.remove(rowIndex);
            changeListener.changed();
            return;
        }

        // If document was locally updated, then remove it from documentsUpdated
        // and let it go into documentsDeleted.
        if (documentsUpdated.contains(document)) {
            documentsUpdated.remove(document);
        }

        // Remove document.
        documentsDeleted.add(document);
        table.getItem(rowIndex).setBackground(RED);
        changeListener.changed();
    }

    /**
     * Add a document locally.
     *
     * @param document
     *            The new document.
     */
    public void addDocument(SolrDocument document) {
        documentsAdded.add(document);
        table.setItemCount(table.getItemCount() + 1);
        // Scroll to the bottom of the table so we reveal the new document.
        table.setTopIndex(table.getItemCount() - 1);
        changeListener.changed();
    }

    /**
     * Add a new (custom) column to the table.
     *
     * This is used for dynamic fields, where field name may be "ss_*" but we
     * want the column name to be "ss_foobar".
     *
     * @param fieldName
     *            New field name.
     * @param fieldInfo
     *            New field definition.
     */
    private void addColumn(final String fieldName, FieldInfo fieldInfo) {
        final TableColumn column = new TableColumn(table, SWT.LEFT);
        // Add space padding so we can see the sort signifier.
        final boolean isFieldSortable = SolrUtils.isFieldSortable(fieldInfo);
        column.setText(fieldName + (isFieldSortable ? "     " : " " + Sophie.SIGNIFIER_UNSORTABLE));
        column.setData("field", fieldInfo);
        column.setData("fieldName", fieldName);
        if (!isFieldSortable) {
            column.setToolTipText("Cannot sort on a field that is not indexed, is multivalued or has doc values");
        }
        // Sort column when click on the header
        column.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent event) {
                if (!isFieldSortable) {
                    return;
                }
                // Clicking on the current sort field toggles the direction.
                // Clicking on a new field changes the sort field.
                if (StringUtils.equals(sortField, fieldName)) {
                    sortOrder = ORDER.asc.equals(sortOrder) ? ORDER.desc : ORDER.asc;
                } else {
                    sortField = fieldName;
                }
                // Clear signifier on all columns, add signifier on sorted
                // column.
                char signifier = ORDER.asc.equals(sortOrder) ? Sophie.SIGNIFIER_SORTED_ASC : Sophie.SIGNIFIER_SORTED_DESC;
                for (TableColumn c : table.getColumns()) {
                    String columnFieldName = (String) c.getData("fieldName");
                    FieldInfo columnField = (FieldInfo) c.getData("field");
                    if (columnFieldName != null && columnField != null) {
                        if (!SolrUtils.isFieldSortable(columnField)) {
                            c.setText(columnFieldName + " " + Sophie.SIGNIFIER_UNSORTABLE);
                        } else {
                            c.setText(columnFieldName + ((column == c) ? " " + signifier : StringUtils.EMPTY));
                        }
                    }

                }
                // Re-populate table.
                try {
                    refresh();
                } catch (SophieException e) {
                    ExceptionDialog.open(composite.getShell(), new SophieException("Unable to refresh documents from Solr server", e));
                }
            }
        });
        column.pack();
    }

    /**
     * Add a filter (combo).
     *
     * @param fieldName
     *            Field name.
     * @param field
     *            Field definition.
     * @param facet
     *            Facet - the values will be used to populate the values of the
     *            combo.
     * @param index
     *            Column index.
     */
    private void addCombo(String fieldName, FieldInfo field, final FacetField facet, int index) {
        final CCombo combo = new CCombo(table, SWT.BORDER);
        combo.add(StringUtils.EMPTY);
        // If the number of facet values is the max, then the list of facet
        // values might not be complete. Hence we use a free text field instead
        // of populating the combo.
        if (facet.getValueCount() < FACET_LIMIT) {
            for (Count count : facet.getValues()) {
                combo.add(Objects.toString(count.getName(), LABEL_EMPTY) + " (" + count.getCount() + ")");
            }
            combo.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent event) {
                    // Extract original value (e.g. "Foobar") from widget value
                    // (e.g. "Foobar (3)")
                    Pattern pattern = Pattern.compile("^(.*) \\([0-9]+\\)$");
                    Matcher matcher = pattern.matcher(combo.getText());
                    // If we found the original value, then populate the combo.
                    // Otherwise, log a warning message.
                    if (matcher.find()) {
                        combo.setText(matcher.group(1));
                    } else {
                        Sophie.log.warn("Unable to extract original value from \"" + combo.getText() + "\"");
                    }

                };
            });
        } else {
            combo.add(LABEL_EMPTY);
        }

        // Fire filters + refresh when user selects a value.
        combo.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent event) {
                String filterName = facet.getName();
                String filterNewValue = combo.getText();
                String filterOldValue = filters.get(filterName);
                // No need to re-send a request to Solr and the user selected
                // the same filter as the current filter.
                if (StringUtils.equals(filterOldValue, filterNewValue) || (StringUtils.isBlank(filterOldValue) && StringUtils.isBlank(filterNewValue))) {
                    return;
                }
                updateFilters(filterName, filterNewValue);
                try {
                    refresh();
                } catch (SophieException e) {
                    ExceptionDialog.open(composite.getShell(), new SophieException("Unable to refresh documents from Solr server", e));
                }
            }
        });

        // Filter (refresh) results when user hits "Enter" while editing one of
        // the combos.
        combo.addListener(SWT.KeyUp, new Listener() {
            @Override
            public void handleEvent(Event event) {
                if (event.character == SWT.CR) {
                    updateFilters(facet.getName(), combo.getText());
                    try {
                        refresh();
                    } catch (SophieException e) {
                        ExceptionDialog.open(composite.getShell(), new SophieException("Unable to refresh documents from Solr server", e));
                    }
                }
            }
        });
        if (combo != null) {
            editor.grabHorizontal = true;
            editor.setEditor(combo, table.getItem(0), index);
            editor = new TableEditor(table);
        }
    }

    /**
     * Add a new field to the table.
     *
     * @param fieldName
     *            Field name.
     * @param field
     *            Field definition.
     * @param facet
     *            Facet - the values will be used to populate the values of the
     *            combo.
     * @param index
     *            Column index.
     */
    private void addField(String fieldName, FieldInfo field, FacetField facet, int index) {
        addColumn(fieldName, field);
        // If field or facet is null then we cannot filter on this field (e.g.
        // the field is not indexed).
        if (fieldName != null && field != null && facet != null) {
            addCombo(fieldName, field, facet, index);
        }
    }

    /**
     * Add a new field to the table. The field name is deduced from the field
     * definition.
     *
     * @param field
     *            Field definition.
     * @param facet
     *            Facet - the values will be used to populate the values of the
     *            combo.
     * @param index
     *            Column index.
     */
    private void addField(FieldInfo field, FacetField facet, int index) {
        addField(field.getName(), field, facet, index);
    }

    /**
     * Add new field to the table. No values are provided to the filter.
     *
     * @param fieldName
     *            Field name.
     * @param field
     *            Field definition.
     */
    public void addField(String fieldName, FieldInfo field) {
        FacetField facet = new FacetField(fieldName);
        int index = table.getColumnCount();
        addField(fieldName, field, facet, index);
    }

}


text:
package com.example.gcpsupport;

// [START gcpsupport_starter]

import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.cloudsupport.v2beta.CloudSupport;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;

// starter code for cloud support API to initialize it
public class Starter {

  // Shared constants
  static final String CLOUD_SUPPORT_SCOPE = "https://www.googleapis.com/auth/cloudsupport";

  public static void main(String[] args) {

    try {
      CloudSupport cloudSupport = getCloudSupportService();
      // with the CloudSupport object, you may call other methods of the Support API
      // for example, cloudSupport.cases().get("name of case").execute();

      System.out.println("CloudSupport API is ready to use: " + cloudSupport);

    } catch (IOException e) {
      System.out.println("IOException caught! \n" + e);

    } catch (GeneralSecurityException e) {
      System.out.println("GeneralSecurityException caught! \n" + e);
    }
  }

  // helper method will return a CloudSupport object which is required for the
  // main API service to be used.
  public static CloudSupport getCloudSupportService() throws IOException, GeneralSecurityException {

    JsonFactory jsonFactory = GsonFactory.getDefaultInstance();
    HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();

    // this will only work if you have already set the environment variable
    // GOOGLE_APPLICATION_CREDENTIALS to point to the path with your service account
    // key
    GoogleCredentials credentials =
        GoogleCredentials.getApplicationDefault()
            .createScoped(Collections.singletonList(CLOUD_SUPPORT_SCOPE));
    HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials);

    return new CloudSupport.Builder(httpTransport, jsonFactory, requestInitializer).build();
  }
}

// [END gcpsupport_starter]

redpajama_set_name: RedPajamaGithub


text:
<?php

namespace Crivero\PruebaBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

class EquipoController extends Controller {

    public function equiposAction(Request $request) {
       $repository = $this->getDoctrine()->getRepository("CriveroPruebaBundle:Equipos");
       $searchQuery = $request->get('query');
        (!empty($searchQuery)) ? $equipos = $repository->searchEquipos($searchQuery) :
                                 $equipos = $repository->findAll();
       $paginator = $this->get('knp_paginator');
       $pagination = $paginator->paginate(
                $equipos, $request->query->getInt('page', 1), 4);
       $repositoryCompeticiones = $this->getDoctrine()->getRepository("CriveroPruebaBundle:Competiciones");
       $repositoryUsuarios = $this->getDoctrine()->getRepository("CriveroPruebaBundle:Usuarios");
       $competiciones = array();
       $representantes = array();
       foreach ($equipos as $equipo=>$valor){
            $competiciones[$valor->getIdCompeticion()] = $repositoryCompeticiones->find($valor->getIdCompeticion());
            $representantes[$valor->getIdCliente()] = $repositoryUsuarios->find($valor->getIdCliente());
       }
       return $this->render('CriveroPruebaBundle:Competiciones:equipos.html.twig', array("notificacionesSinLeer"=>$this->getNewNotification(),"equipos"=>$pagination,
           "competiciones"=>$competiciones,"representantes"=>$representantes));
    }

    public function equipoAction(Request $request,$id) {
      $repositoryEquipo = $this->getDoctrine()->getRepository("CriveroPruebaBundle:Equipos");
      $equipo=$repositoryEquipo->find($id);
      $searchQuery = $request->get('query');
      $repositorioJugadores = $this->getDoctrine()->getRepository("CriveroPruebaBundle:Jugadores");
      (!empty($searchQuery)) ? $jugadores = $repositorioJugadores->searchJugadores($searchQuery) :
                        $jugadores = $repositorioJugadores->findJugadoresEquipo($id);
      $paginator = $this->get('knp_paginator');
      $pagination = $paginator->paginate(
                $jugadores, $request->query->getInt('page', 1), 4);
      return $this->render('CriveroPruebaBundle:Competiciones:equipo.html.twig', array("notificacionesSinLeer"=>$this->getNewNotification(),"equipo"=>$equipo,"jugadores"=>$pagination));
    }

    private function getNewNotification() {
        $repositoryN = $this->getDoctrine()->getRepository("CriveroPruebaBundle:Notificaciones");
        $notificaciones = $repositoryN->getNotificaciones($this->getUser()->getId());
        $notificacionesSinLeer = array();
        foreach ($notificaciones as $clave => $notificacion) {
            if ($notificacion->getEstado() == "No leido") {
                $notificacionesSinLeer[$clave] = $notificacion;
            }
        }
        return $notificacionesSinLeer;
    }
}


text:
<!DOCTYPE html>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <title>Arrays — Zephir documentation</title>
    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
    <link href="google/g.css" rel="stylesheet" type="text/css" />
    <link rel="stylesheet" href="_static/docs.css" type="text/css" />

    <link rel="shortcut icon" href="_static/favicon.ico"/>
    <link rel="top" title="Zephir documentation" href="index.html" />
    <link rel="next" title="Classes and Objects" href="oop.html" />
    <link rel="prev" title="Operators" href="operators.html" />

          index

          next |

          previous |

Home »

Zephir documentation »

Table Of Contents

Arrays

Declaring Array Variables

Creating Arrays

Updating arrays

Appending elements

Reading elements from arrays

Previous topic

< Operators

Next topic

Classes and Objects >

This Page

Show Source

Arrays¶

Array manipulation in Zephir provides a way to use PHP arrays.
An array is an implementation of a hash table.

Declaring Array Variables¶

Array variables can be declared using the keywords ‘var’ or ‘array’:

var a = []; // array variable, its type can be changed
array b = []; // array variable, its type cannot be changed across execution

Creating Arrays¶

An array is created enclosing their elements in square brackets:

//Creating an empty array
let elements = [];

//Creating an array with elements
let elements = [1, 3, 4];

//Creating an array with elements of different types
let elements = ["first", 2, true];

//A multidimensional array
let elements = [[0, 1], [4, 5], [2, 3]];

As PHP, hashes or dictionaries are supported:

//Creating a hash with string keys
let elements = ["foo": "bar", "bar": "foo"];

//Creating a hash with numeric keys
let elements = [4: "bar", 8: "foo"];

//Creating a hash with mixed string and numeric keys
let elements = [4: "bar", "foo": 8];

Updating arrays¶

Arrays are updated in the same way as PHP using square brackets:

//Updating an array with a string key
let elements["foo"] = "bar";

//Updating an array with a numeric key
let elements[0] = "bar";

//Updating multi-dimensional array
let elements[0]["foo"] = "bar";
let elements["foo"][0] = "bar";

Appending elements¶

Elements can be appended at the end of the array as follows:

//Append an element to the array
let elements[] = "bar";

Reading elements from arrays¶

Is possible to read array elements as follows:

//Getting an element using the string key "foo"
let foo = elements["foo"];

//Getting an element using the numeric key 0
let foo = elements[0];

          index

          next |

          previous |

Zephir Language is an open source project licensed under
            MIT license.

Except where otherwise noted, content on this site is licensed under the
            Creative Commons Attribution 3.0 License.

             Last updated on Apr 27, 2014.
            V0.4.2 GitHub

             © Copyright 2013-2014, Zephir Team.


text:
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main"><source path="C:\Users\v\Desktop\A_S_workspace\TheBible\app\src\androidTest\assets"/></dataSet></merger>


text:
/*!
 * V4Fire Client Core
 * https://github.com/V4Fire/Client
 *
 * Released under the MIT license
 * https://github.com/V4Fire/Client/blob/master/LICENSE
 */

import type { JSHandle, Cookie } from 'playwright';

import type * as Cookies from 'core/cookies';

import test from 'tests/config/unit/test';
import Utils from 'tests/helpers/utils';

test.describe('core/cookies', () => {
	let
		cookie: JSHandle<typeof Cookies>;

	test.beforeEach(async ({demoPage, page}) => {
		await demoPage.goto();
		cookie = await Utils.import(page, 'core/cookies');
	});

	test.describe('`get`', () => {
		test.beforeEach(async () => {
			await cookie.evaluate((ctx) => ctx.set('testCookie', 'testCookieVal'));
		});

		test('returns a cookie value', async () => {
			const
				testVal = await cookie.evaluate((ctx) => ctx.get('testCookie'));

			test.expect(testVal).toBe('testCookieVal');
		});

		test('returns `undefined` when trying to get a value of the non-existent cookie', async () => {
			const
				testVal = await cookie.evaluate((ctx) => ctx.get('unreachableCookie'));

			test.expect(testVal).toBeUndefined();
		});
	});

	test.describe('`has`', () => {
		test.beforeEach(async () => {
			await cookie.evaluate((ctx) => ctx.set('testCookie', 'testCookieVal'));
		});

		test('returns `true` if the cookie exists', async () => {
			const
				testVal = await cookie.evaluate((ctx) => ctx.has('testCookie'));

			test.expect(testVal).toBe(true);
		});

		test('returns `false` if the cookie does not exist', async () => {
			const
				testVal = await cookie.evaluate((ctx) => ctx.has('unreachableCookie'));

			test.expect(testVal).toBe(false);
		});
	});

	test.describe('`set`', () => {
		test('simple usage', async ({page}) => {
			await cookie.evaluate((ctx) => ctx.set('testCookie', 'testCookieVal'));

			const
				testVal = await page.evaluate(() => document.cookie);

			test.expect(testVal).toBe('testCookie=testCookieVal');
		});

		test('set multiply cookies', async ({context, page}) => {
			await cookie.evaluate((ctx) => ctx.set('testCookie', 'testCookieVal'));
			await cookie.evaluate((ctx) => ctx.set('testCookie2', 'testCookieVal2'));

			const
				cookies = await context.cookies(page.url());

			test.expect(cookies).toEqual([
				createCookie(),
				createCookie({
					name: 'testCookie2',
					value: 'testCookieVal2'
				})
			]);
		});

		test('with the `path` option provided', async ({page, context}) => {
			await cookie.evaluate((ctx) => ctx.set('testCookie', 'testCookieVal', {path: '/test'}));

			const
				origin = await page.evaluate(() => location.origin),
				cookies = await context.cookies(`${origin}/test`);

			test.expect(cookies).toEqual([createCookie({path: '/test'})]);
		});

		test('with the `expires` option provided', async ({page, context}) => {
			const expires = await page.evaluate(() => {
				globalThis._expDate = new Date(Date.now() + 86400e3);
				return Math.floor(globalThis._expDate.getTime() / 1000);
			});

			await cookie.evaluate((ctx) => ctx.set('testCookie', 'testCookieVal', {expires: globalThis._expDate}));

			const
				cookies = await context.cookies(page.url());

			test.expect(cookies).toEqual([createCookie({expires})]);
		});
	});

	test.describe('`remove`', () => {
		test('removes a cookie', async ({context, page}) => {
			await cookie.evaluate((ctx) => ctx.set('testCookie', 'testCookieVal'));
			await cookie.evaluate((ctx) => ctx.remove('testCookie'));

			const
				cookies = await context.cookies(page.url());

			test.expect(cookies).toEqual([]);
		});
	});

	function createCookie(params: Dictionary = {}): Cookie {
		return {
			sameSite: 'Lax',
			name: 'testCookie',
			value: 'testCookieVal',
			domain: 'localhost',
			path: '/',
			expires: -1,
			httpOnly: false,
			secure: false,
			...params
		};
	}
});


text:
using System;
using MbUnit.Framework;

namespace CSharpSharp.Tests
{
    /// <summary>
    /// Validates the DateTime sharp properties, methods and extension methods.
    /// </summary>
    public class DateTimeSharpFixture
    {
        /// <summary>
        /// Validates that the MillisecondsSinceUNIXTime property returns the expected value.
        /// </summary>
        [Test]
        public void MillisecondsSinceUNIXTime()
        {
            double millisecondsSinceUNIXTime = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
            double actualMillisecondsSinceUNIXTime = DateTimeSharp.MillisecondsSinceUNIXTime;

            Assert.AreApproximatelyEqual(millisecondsSinceUNIXTime, actualMillisecondsSinceUNIXTime, (double)5, "Actual delta: {0}", actualMillisecondsSinceUNIXTime - millisecondsSinceUNIXTime);
        }

        /// <summary>
        /// Validates that the tomorrow property returns the expected date time.
        /// </summary>
        [Test]
        public void Tomorrow()
        {
            DateTime tomorrow = DateTimeSharp.Tomorrow;

            Assert.AreEqual(DateTime.Today + new TimeSpan(1, 0, 0, 0), tomorrow);
        }

        /// <summary>
        /// Validates that the yesterday property returns the expected date time.
        /// </summary>
        [Test]
        public void Yesterday()
        {
            DateTime yesterday = DateTimeSharp.Yesterday;

            Assert.AreEqual(DateTime.Today - new TimeSpan(1, 0, 0, 0), yesterday);
        }

        /// <summary>
        /// Validates that the integer.Seconds() shorthand returns a TimeSpan
        /// of the number of seconds specified by the integer.
        /// </summary>
        [Test]
        public void SecondsShorthand()
        {
            TimeSpan fiveSeconds = 5.Seconds();

            Assert.AreEqual(new TimeSpan(0, 0, 5), fiveSeconds);
        }

        /// <summary>
        /// Validates that the integer.Minutes() shorthand returns a TimeSpan
        /// of the number of minutes specified by the integer.
        /// </summary>
        [Test]
        public void MinutesShorthand()
        {
            TimeSpan fiveMinutes = 5.Minutes();

            Assert.AreEqual(new TimeSpan(0, 5, 0), fiveMinutes);
        }

        /// <summary>
        /// Validates that the integer.Hours() shorthand returns a TimeSpan
        /// of the number of hours specified by the integer.
        /// </summary>
        [Test]
        public void HoursShorthand()
        {
            TimeSpan fiveHours = 5.Hours();

            Assert.AreEqual(new TimeSpan(5, 0, 0), fiveHours);
        }

        /// <summary>
        /// Validates that the integer.Days() shorthand returns a TimeSpan
        /// of the number of days specified by the integer.
        /// </summary>
        [Test]
        public void DaysShorthand()
        {
            TimeSpan fiveDays = 5.Days();

            Assert.AreEqual(new TimeSpan(5, 0, 0, 0), fiveDays);
        }

        /// <summary>
        /// Validates that the integer.Months() shorthand returns a TimeSpan
        /// of the number of months specified by the integer.
        /// </summary>
        [Test]
        public void MonthsShorthand()
        {
            TimeSpan fiveMonths = 5.Months();

            int numberOfDays = (int)(5 * DateTimeSharp.DaysInAMonth);

            Assert.AreEqual(new TimeSpan(numberOfDays, 0, 0, 0), fiveMonths);
        }

        /// <summary>
        /// Validates that the integer.Months(true) shorthand returns a TimeSpan
        /// of the number of months specified by the integer.
        /// </summary>
        [Test]
        public void MonthsShorthandAssumption()
        {
            TimeSpan sixtyMonthsWithAssumption = 60.Months(true);
            TimeSpan sixtyMonthsWithoutAssumption = 60.Months();

            // Make sure they are not the same
            Assert.AreNotEqual(sixtyMonthsWithAssumption, sixtyMonthsWithoutAssumption);

            // Compare with a manually calculated number of days
            TimeSpan sixtyMonthsOf30Days = new TimeSpan(60 * 30, 0, 0, 0);
            Assert.AreEqual(sixtyMonthsWithAssumption, sixtyMonthsOf30Days);
        }

        /// <summary>
        /// Validates that the integer.Years() shorthand returns a TimeSpan
        /// of the number of years specified by the integer.
        /// </summary>
        [Test]
        public void YearsShorthand()
        {
            TimeSpan fiveYears = 5.Years();

            int numberOfDays = (int)(5 * DateTimeSharp.DaysInAYear);

            Assert.AreEqual(new TimeSpan(numberOfDays, 0, 0, 0), fiveYears);
        }

        /// <summary>
        /// Validates that the integer.Years(true) shorthand returns a TimeSpan
        /// of the number of months specified by the integer.
        /// </summary>
        [Test]
        public void YearsShorthandAssumption()
        {
            TimeSpan tenYearsWithAssumption = 10.Years(true);
            TimeSpan tenYearsWithoutAssumption = 10.Years();

            // Make sure they are not the same
            Assert.AreNotEqual(tenYearsWithAssumption, tenYearsWithoutAssumption);

            // Compare with a manually calculated number of days
            TimeSpan tenYearsOf365Days = new TimeSpan(10 * 365, 0, 0, 0);
            Assert.AreEqual(tenYearsWithAssumption, tenYearsOf365Days);
        }

        /// <summary>
        /// Validates that trying to set a number of months that results
        /// in an overflow raises an exception.
        /// </summary>
        [Test]
        [ExpectedException(typeof(OverflowException))]
        public void MonthsOverflow()
        {
            ((int)(int.MaxValue / DateTimeSharp.DaysInAMonth) + 1).Months();
        }

        /// <summary>
        /// Validates that trying to set a number of years that results
        /// in an overflow raises an exception.
        /// </summary>
        [Test]
        [ExpectedException(typeof(OverflowException))]
        public void YearsOverflow()
        {
            ((int)(int.MaxValue / DateTimeSharp.DaysInAYear) + 1).Years();
        }

        /// <summary>
        /// Validates that the timeSpan.Ago() shorthand returns DateTime.Now - TimeSpan.
        /// </summary>
        [Test]
        public void TimeSpanAgo()
        {
            DateTime fiveMinutesAgo = 5.Minutes().Ago();

            Assert.AreApproximatelyEqual(DateTime.Now - new TimeSpan(0, 5, 0), fiveMinutesAgo, new TimeSpan(0, 0, 1));
        }

        /// <summary>
        /// Validates that the timeSpan.FromNow() shorthand returns DateTime.Now + TimeSpan.
        /// </summary>
        [Test]
        public void TimeSpanFromNow()
        {
            DateTime threeHoursFromNow = 3.Hours().FromNow();

            Assert.AreApproximatelyEqual(DateTime.Now + new TimeSpan(3, 0, 0), threeHoursFromNow, new TimeSpan(0, 0, 1));
        }
    }
}


text:
using Common.Log;
using Lykke.Service.EthereumCore.BusinessModels.PrivateWallet;
using Lykke.Service.EthereumCore.Core.Exceptions;
using Lykke.Service.EthereumCore.Models;
using Lykke.Service.EthereumCore.Models.Models;
using Lykke.Service.EthereumCore.Services.PrivateWallet;
using Lykke.Service.EthereumCore.Utils;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.Numerics;
using System.Threading.Tasks;

namespace Lykke.Service.EthereumCore.Controllers
{
    [Route("api/erc20Wallet")]
    [Produces("application/json")]
    public class Erc20WalletController : Controller
    {
        private readonly ILog _log;
        private IErc20PrivateWalletService _erc20Service;

        public Erc20WalletController(IErc20PrivateWalletService erc20Service, ILog log)
        {
            _erc20Service = erc20Service;
            _log = log;
        }

        [HttpPost("getTransaction")]
        [ProducesResponseType(typeof(EthTransactionRaw), 200)]
        [ProducesResponseType(typeof(ApiException), 400)]
        [ProducesResponseType(typeof(ApiException), 500)]
        public async Task<IActionResult> GetTransaction([FromBody]PrivateWalletErc20Transaction ercTransaction)
        {
            if (!ModelState.IsValid)
            {
                throw new ClientSideException(ExceptionType.WrongParams, JsonConvert.SerializeObject(ModelState.Errors()));
            }

            string serialized = JsonConvert.SerializeObject(ercTransaction);
            await _log.WriteInfoAsync("PrivateWalletController", "GetTransaction", serialized, "Get transaction for signing", DateTime.UtcNow);

            Erc20Transaction transaction = new Erc20Transaction()
            {
                TokenAddress = ercTransaction.TokenAddress,
                TokenAmount = BigInteger.Parse(ercTransaction.TokenAmount),
                FromAddress = ercTransaction.FromAddress,
                GasAmount = BigInteger.Parse(ercTransaction.GasAmount),
                GasPrice = BigInteger.Parse(ercTransaction.GasPrice),
                ToAddress = ercTransaction.ToAddress,
                Value = BigInteger.Parse(ercTransaction.Value),
            };
            await _erc20Service.ValidateInput(transaction);
            string transactionHex = await _erc20Service.GetTransferTransactionRaw(transaction);

            await _log.WriteInfoAsync("PrivateWalletController", "GetTransaction", $"{serialized} + TransactionHex:{transactionHex}",
                "Recieved transaction for signing", DateTime.UtcNow);

            return Ok(new EthTransactionRaw()
            {
                FromAddress = ercTransaction.FromAddress,
                TransactionHex = transactionHex
            });
        }

        [HttpPost("submitTransaction")]
        [ProducesResponseType(typeof(HashResponse), 200)]
        [ProducesResponseType(typeof(ApiException), 400)]
        [ProducesResponseType(typeof(ApiException), 500)]
        public async Task<IActionResult> SubmitSignedTransaction([FromBody]PrivateWalletEthSignedTransaction ethTransactionSigned)
        {
            if (!ModelState.IsValid)
            {
                throw new ClientSideException(ExceptionType.WrongParams, JsonConvert.SerializeObject(ModelState.Errors()));
            }

            string serialized = JsonConvert.SerializeObject(ethTransactionSigned);
            await _log.WriteInfoAsync("Erc20WalletController", "SubmitSignedTransaction", serialized
                , "StartSubmitSignedTransaction", DateTime.UtcNow);

            string transactionHash = await _erc20Service.SubmitSignedTransaction(ethTransactionSigned.FromAddress, ethTransactionSigned.SignedTransactionHex);

            await _log.WriteInfoAsync("Erc20WalletController", "SubmitSignedTransaction",
                $"{serialized}-TransactionHash:{transactionHash}", "EndSubmitSignedTransaction", DateTime.UtcNow);

            return Ok(new HashResponse()
            {
                HashHex = transactionHash
            });
        }
    }
}


text:
package controllers

import helpers.TestWithApplication
import Common.PrototypeHtml
import helpers.acquire.CookieFactoryForUnitSpecs
import helpers.UnitSpec
import models.AcquireCacheKeyPrefix.CookiePrefix
import models.IdentifierCacheKey
import org.mockito.Mockito.when
import pages.acquire.BusinessChooseYourAddressPage
import pages.acquire.SetupTradeDetailsPage.{TraderBusinessNameValid, PostcodeValid, TraderEmailValid}
import play.api.test.FakeRequest
import play.api.test.Helpers.{BAD_REQUEST, contentAsString, defaultAwaitTimeout, LOCATION, OK}
import uk.gov.dvla.vehicles.presentation.common
import common.clientsidesession.ClientSideSessionFactory
import common.mappings.{OptionalToggle, BusinessName}
import common.model.SetupTradeDetailsFormModel
import common.mappings.Email.{EmailId, EmailVerifyId}
import common.model.SetupTradeDetailsFormModel.setupTradeDetailsCacheKey
import common.model.SetupTradeDetailsFormModel.Form.{TraderNameId, TraderEmailId, TraderEmailOptionId, TraderPostcodeId}
import common.testhelpers.CookieHelper.fetchCookiesFromHeaders
import common.testhelpers.JsonUtils.deserializeJsonToModel
import utils.helpers.Config

class SetupTradeDetailsUnitSpec extends UnitSpec {

  "present" should {
    "display the page" in new TestWithApplication {
      whenReady(present) { r =>
        r.header.status should equal(OK)
      }
    }

   "not contain an identifier cookie if default route" in new TestWithApplication {
      whenReady(present) { r =>
        val cookies = fetchCookiesFromHeaders(r)
        cookies.find(_.name == IdentifierCacheKey) should equal(None)
      }
    }

    "contain an identifier cookie of type ceg if ceg route" in new TestWithApplication {
      val result = setUpTradeDetails.ceg(FakeRequest())
      whenReady(result) { r =>
        val cookies = fetchCookiesFromHeaders(r)
        cookies.find(_.name == IdentifierCacheKey).get.value should equal(setUpTradeDetails.identifier)
      }
    }

    "display populated fields when cookie exists" in new TestWithApplication {
      val request = FakeRequest().
        withCookies(CookieFactoryForUnitSpecs.setupTradeDetails())
      val result = setUpTradeDetails.present(request)
      val content = contentAsString(result)
      content should include(TraderBusinessNameValid)
      content should include(PostcodeValid)
    }

    "display empty fields when cookie does not exist" in new TestWithApplication {
      val content = contentAsString(present)
      content should not include TraderBusinessNameValid
      content should not include PostcodeValid
    }

    "display prototype message when config set to true" in new TestWithApplication {
      contentAsString(present) should include(PrototypeHtml)
    }

    "not display prototype message when config set to false" in new TestWithApplication {
      val request = FakeRequest()
      implicit val clientSideSessionFactory = injector.getInstance(classOf[ClientSideSessionFactory])
      implicit val config: Config = mock[Config]
      when(config.isPrototypeBannerVisible).thenReturn(false)
      when(config.googleAnalyticsTrackingId).thenReturn(None)
      when(config.assetsUrl).thenReturn(None)
      // Stub this config value.
      val setUpTradeDetailsPrototypeNotVisible = new SetUpTradeDetails()

      val result = setUpTradeDetailsPrototypeNotVisible.present(request)
      contentAsString(result) should not include PrototypeHtml
    }
  }

    "submit" should {
      "redirect to next page when the form is completed successfully" in new TestWithApplication {
        val request = buildCorrectlyPopulatedRequest()
        val result = setUpTradeDetails.submit(request)
        whenReady(result) { r =>
          r.header.headers.get(LOCATION) should equal(Some(BusinessChooseYourAddressPage.address))
          val cookies = fetchCookiesFromHeaders(r)
          val cookieName = setupTradeDetailsCacheKey
          cookies.find(_.name == cookieName) match {
            case Some(cookie) =>
              val json = cookie.value
              val model = deserializeJsonToModel[SetupTradeDetailsFormModel](json)
              model.traderBusinessName should equal(TraderBusinessNameValid.toUpperCase)
              model.traderPostcode should equal(PostcodeValid.toUpperCase)
            case None => fail(s"$cookieName cookie not found")
          }
        }
      }

      "return a bad request if no details are entered" in new TestWithApplication {
        val request = buildCorrectlyPopulatedRequest(dealerName = "", dealerPostcode = "")
        val result = setUpTradeDetails.submit(request)
        whenReady(result) { r =>
          r.header.status should equal(BAD_REQUEST)
        }
      }

      "replace max length error message for traderBusinessName with standard error message " in new TestWithApplication {
        val request = buildCorrectlyPopulatedRequest(dealerName = "a" * (BusinessName.MaxLength + 1))
        val result = setUpTradeDetails.submit(request)
        contentAsString(result) should include("Must be between 2 and 58 characters and only contain valid characters")
      }

      "replace required and min length error messages for traderBusinessName with standard error message " in new TestWithApplication {
        val request = buildCorrectlyPopulatedRequest(dealerName = "")
        val result = setUpTradeDetails.submit(request)
        val count = "Must be between 2 and 58 characters and only contain valid characters"
          .r.findAllIn(contentAsString(result)).length
        count should equal(2)
      }
    }

  private def buildCorrectlyPopulatedRequest(dealerName: String = TraderBusinessNameValid,
                                             dealerPostcode: String = PostcodeValid,
                                             dealerEmail: Option[String] = Some(TraderEmailValid)) = {
    FakeRequest().withFormUrlEncodedBody(Seq(
      TraderNameId -> dealerName,
      TraderPostcodeId -> dealerPostcode
    ) ++ dealerEmail.fold(Seq(TraderEmailOptionId -> OptionalToggle.Invisible)) { email =>
      Seq(
        TraderEmailOptionId -> OptionalToggle.Visible,
        s"$TraderEmailId.$EmailId" -> email,
        s"$TraderEmailId.$EmailVerifyId" -> email
      )
    }:_*)
  }

  private lazy val setUpTradeDetails = {
    injector.getInstance(classOf[SetUpTradeDetails])
  }

  private lazy val present = {
    val request = FakeRequest()
    setUpTradeDetails.present(request)
  }
}


text:
import { injectGlobal } from 'styled-components';

/* eslint no-unused-expressions: 0 */
injectGlobal`
  html,
  body {
    height: 100%;
    width: 100%;
    font-family: 'Kaushan Script', cursive;
  }

  body {
  }

  body.fontLoaded {
    font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  }

  #app {
    background-color: #fafafa;
    min-height: 100%;
    min-width: 100%;
  }

  p,
  label {
    font-family: Georgia, Times, 'Times New Roman', serif;
    line-height: 1.5em;
  }
`;


text:
package org.relib.db;

/**
 * Represents a generic SQL exception
 *
 * @author Troy Histed
 */
public class DaoException extends RuntimeException {

	private static final long serialVersionUID = -6056741171142667158L;

	/**
	 * Creates a DaoException.
	 *
	 * @param description
	 *            Description of the exception
	 */
	public DaoException(String description) {
		super(description);
	}

	/**
	 * Creates a DaoException.
	 *
	 * @param description
	 *            Description of the exception
	 * @param exception
	 *            original exception
	 */
	public DaoException(String description, Throwable exception) {
		super(description, exception);
	}
}


text:
import { ReadStream } from 'fs';
import * as tarStream from 'tar-stream';

export function pack(cwd: string, opts?: PackOptions): tarStream.Pack;
export function extract(cwd: string, opts?: ExtractOptions): tarStream.Extract;

export type Pack = tarStream.Pack;
export type Extract = tarStream.Extract;

export interface Options {
    ignore?: (name: string) => boolean;
    filter?: (name: string) => boolean;
    map?: (header: Headers) => Headers;
    mapStream?: (fileStream: ReadStream, header: Headers) => ReadStream;
    dmode?: number;
    fmode?: number;
    readable?: boolean;
    writable?: boolean;
    strict?: boolean;
}

export interface PackOptions extends Options {
    entries?: string[];
    dereference?: boolean;
    finalize?: boolean;
    finish?: (pack: tarStream.Pack) => void;
    pack?: tarStream.Pack;
}

export interface ExtractOptions extends Options {
    ignore?: (name: string, header?: Headers) => boolean;
    filter?: (name: string, header?: Headers) => boolean;
    strip?: number;
}

export interface Headers {
    name: string;
    mode: number;
    mtime: Date;
    size: number;
    type: 'file' | 'directory' | 'link' | 'symlink';
    uid: number;
    gid: number;
}