text:
package org.blackchip.scorebored;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import org.apache.log4j.Logger;
import org.blackchip.scorebored.swing.Swing;
import org.blackchip.scorebored.swing.TextRenderer;
import org.blackchip.scorebored.swing.WindowManager;
import org.blackchip.scorebored.talker.Speech;
import org.blackchip.scorebored.talker.SwingTalker;
import org.blackchip.scorebored.talker.TalkListener;
import org.blackchip.scorebored.util.Strings;

public class ScoreboardFrame extends javax.swing.JFrame {

    private static final boolean DEBUG_LAYOUT = false;

    private static final Logger log =
            Logger.getLogger(ScoreboardFrame.class);

    private static final GraphicsEnvironment graphicsEnvironment =
            GraphicsEnvironment.getLocalGraphicsEnvironment();

    private WindowManager windowManager = WindowManager.getInstance();
    private SwingTalker talker;
    private Match match;
    private KeyboardControl keyboardControl = new KeyboardControl();
    private TextRenderer subtitle;
    private boolean keyBindingsEnabled = false;
    private Font teamNameFont;
    private Font scoreFont;
    private JacobExcuses excuses;

    public ScoreboardFrame(final Match match) {

        excuses = JacobExcuses.getInstance();

        this.match = match;
        this.talker = match.getTalker();
        if ( graphicsEnvironment.getDefaultScreenDevice().isFullScreenSupported() ) {
            this.setUndecorated(true);
        }

        teamNameFont = new Font("Inconsolata", Font.BOLD, 64);
        Font teamScoreFont = new Font("Inconsolata", Font.BOLD, 400);

        initComponents();

        if ( DEBUG_LAYOUT ) {
            leftTeamNameText.setBorder(BorderFactory.createLineBorder(Color.YELLOW));
            rightTeamNameText.setBorder(BorderFactory.createLineBorder(Color.YELLOW));
            leftScoreText.setBorder(BorderFactory.createLineBorder(Color.YELLOW));
            rightScoreText.setBorder(BorderFactory.createLineBorder(Color.YELLOW));
            leftWinsText.setBorder(BorderFactory.createLineBorder(Color.YELLOW));
            rightWinsText.setBorder(BorderFactory.createLineBorder(Color.YELLOW));
            leftServerText.setBorder(BorderFactory.createLineBorder(Color.YELLOW));
            rightServerText.setBorder(BorderFactory.createLineBorder(Color.YELLOW));
        }

        subtitle = new TextRenderer(this, 0.5f, 0.9f);

        pack();

        applyStyle();

        this.getRootPane().addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent evt) {
                System.out.println(evt);
            }
        });

        talkText.setText("");

        if ( !graphicsEnvironment.getDefaultScreenDevice()
                .isFullScreenSupported() ) {
            this.setExtendedState(JFrame.MAXIMIZED_BOTH);
        }

        talker.addListener(new TalkListener() {
            @Override
            public void talkStarted(Speech speech) {
                if ( talker.isMute() || match.isSubtitled() ) {
                    subtitle.setText(speech.getDisplayAs());
                    repaint();
                }
            }

            @Override
            public void talkEnded() {
                subtitle.fade(match.getStyle().getSubtitleFadeTime());
                repaint();
            }
        });

        this.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                applyStyle();
            }
        });

        yeahBabyButton.setAction(Actions.YEAH_BABY);
        yeahBabyButton.setText("Yeah");
        noBabyButton.setAction(Actions.NO_BABY);
        noBabyButton.setText("No");
        shhButton.setAction(Actions.SHH);
        shhButton.setText("Shh");
        netButton.setAction(Actions.NOTHING_BUT_NET);
        netButton.setText("Net");
        scoreButton.setAction(Actions.SCORE);
        scoreButton.setText("Score");
        serverButton.setAction(Actions.SERVER);
        serverButton.setText("Server");
        excuseButton.setAction(Actions.RANDOM_EXCUSE);
        excuseButton.setText("Excuse");
        settingsButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                showSettingsDialog();
            }
        });
        settingsButton.setText("Settings");
        muteButton.setAction(Actions.MUTE);
        muteButton.setText("Mute");

    }

    @Override
    public void setVisible(boolean visible) {
        GraphicsDevice graphicsDevice =
                graphicsEnvironment.getDefaultScreenDevice();
        if ( graphicsDevice.isFullScreenSupported() ) {
            if ( visible && match.isFullScreen() ) {
                graphicsDevice.setFullScreenWindow(this);
            } else {
                graphicsDevice.setFullScreenWindow(null);
            }
        }
        super.setVisible(visible);
        if ( visible ) {
            JFrame frame = windowManager.getDashboardFrame();
            frame.setVisible(false);
        }
    }

    public void applyStyle() {
        final Component leftComponents[] = {
            leftTeamNameText, leftScoreText, leftServerText, leftWinsText
        };

        final Component rightComponents[] = {
            rightTeamNameText, rightScoreText, rightServerText, rightWinsText
        };

        Style style = match.getStyle();
        for ( Component c: leftComponents ) {
            c.setBackground(style.getBackgroundColor());
            c.setForeground(match.getTeam(Team.Side.LEFT).getColor().getColor());
        }
        for ( Component c: rightComponents ) {
            c.setBackground(style.getBackgroundColor());
            c.setForeground(match.getTeam(Team.Side.RIGHT).getColor().getColor());
        }

        teamNameFont = style.getTeamFont();

        Team leftTeam = match.getTeam(Team.Side.LEFT);
        if ( match.getServer() == Team.Side.LEFT ) {
            leftTeamNameText.setBackground(leftTeam.getColor().getColor());
            leftTeamNameText.setForeground(match.getStyle().getBackgroundColor());
        } else {
            leftTeamNameText.setForeground(leftTeam.getColor().getColor());
            leftTeamNameText.setBackground(match.getStyle().getBackgroundColor());
        }
        setTextAndFont(teamNameFont, leftTeamNameText, leftTeam.getName().getDisplayAs());
        leftWinsText.setFont(teamNameFont);
        leftServerText.setFont(style.getTeamFont());

        Team rightTeam = match.getTeam(Team.Side.RIGHT);
        if ( match.getServer() == Team.Side.RIGHT ) {
            rightTeamNameText.setBackground(rightTeam.getColor().getColor());
            rightTeamNameText.setForeground(match.getStyle().getBackgroundColor());
        } else {
            rightTeamNameText.setForeground(rightTeam.getColor().getColor());
            rightTeamNameText.setBackground(match.getStyle().getBackgroundColor());
        }
        setTextAndFont(teamNameFont, rightTeamNameText, rightTeam.getName().getDisplayAs());
        rightWinsText.setFont(teamNameFont);
        rightServerText.setFont(style.getTeamFont());

        leftScoreText.setFont(style.getScoreFont());
        rightScoreText.setFont(style.getScoreFont());

        this.getContentPane().setBackground(style.getBackgroundColor());
        final JButton buttons[] = {
            yeahBabyButton, noBabyButton, shhButton, excuseButton,
            settingsButton, closeButton, muteButton, netButton, serverButton,
            scoreButton
        };
        for ( JButton b: buttons ) {
            b.setBackground(style.getBackgroundColor());
            b.setForeground(style.getButtonTextColor());
            b.addMouseListener(new ButtonHighlighter());
        }

        talkText.setBackground(style.getTextBackgroundColor());
        talkText.setForeground(style.getButtonTextColor());
        talkText.setCaretColor(style.getButtonTextColor());

        subtitle.setColor(match.getStyle().getSubtitleColor());
    }

    public void refresh() {
        Team leftTeam = match.getTeam(Team.Side.LEFT);
        setTextAndFont(teamNameFont, leftTeamNameText, leftTeam.getName().getDisplayAs());
        leftScoreText.setText("" + leftTeam.getScore());

        leftServerText.setText(" ");

        //leftServerText.setText(match.getServer() == Team.Side.LEFT
        //        ? "\u21A2" : "");

        Team rightTeam = match.getTeam(Team.Side.RIGHT);
        setTextAndFont(teamNameFont, rightTeamNameText, rightTeam.getName().getDisplayAs());

        rightScoreText.setText("" + rightTeam.getScore());

        rightServerText.setText(" ");
        //rightServerText.setText(match.getServer() == Team.Side.RIGHT
        //        ? "\u21A3" : "");

        if ( match.getMatchLength() == MatchLength.ONE ) {
            leftWinsText.setText(" ");
            rightWinsText.setText(" ");
        } else {
            leftWinsText.setText("" + leftTeam.getWins());
            rightWinsText.setText("" + rightTeam.getWins());
        }

        applyStyle();
    }

    private void setTextAndFont(Font font, JTextField textField, String name) {

        if ( false ) {
            textField.setText(name);
            return;
        }

        Graphics g = this.getGraphics();

        int width = textField.getWidth();

        int actualWidth = (int)g.getFontMetrics(font).getStringBounds(name, g).getWidth();

        //System.out.println(name);
        //System.out.println("Width: " + width + ", actual: " + actualWidth + " font: " + font.getSize());
        while ( actualWidth > width && font.getSize() > 14 ) {
            font = font.deriveFont((float)font.getSize() - 1);
            width = textField.getWidth();
            actualWidth = (int)g.getFontMetrics(font).getStringBounds(name, g).getWidth();
        }
        //System.out.println("Width: " + width + ", actual: " + actualWidth + " font: " + font.getSize());

        font = font.deriveFont((float)font.getSize() - 5);
        textField.setFont(font);
        textField.setText(name);
    }

    private void advanceTeam(Team.Side side) {
        try {
            match.incrementTeamScore(side);
        } catch ( Exception e ) {
            Swing.showError(e);
        }
        refresh();
    }

    private void advanceVictory(Team.Side side) {
        try {
            match.incrementTeamVictory(side);
        } catch ( Exception e ) {
            Swing.showError(e);
        }
        refresh();
    }

    private void retreatTeam(Team.Side side) {
        try {
            match.decrementTeamScore(side);
        } catch ( Exception e ) {
            Swing.showError(e);
        }
        refresh();
    }

    private void retreatVictory(Team.Side side) {
        try {
            match.decrementTeamVictory(side);
        } catch ( Exception e ) {
            Swing.showError(e);
        }
        refresh();
    }

    class KeyboardControl implements KeyEventDispatcher {
        @Override
        public boolean dispatchKeyEvent(KeyEvent ke) {
            if ( ke.getID() == KeyEvent.KEY_RELEASED ) {

                if ( ke.isShiftDown() ) {
                    switch ( ke.getKeyCode() ) {
                        case KeyEvent.VK_RIGHT:
                            if ( !match.isReverse() ) {
                                retreatTeam(Team.Side.RIGHT);
                            } else {
                                retreatTeam(Team.Side.LEFT);
                            }
                            return true;
                        case KeyEvent.VK_LEFT:
                            if ( !match.isReverse() ) {
                                retreatTeam(Team.Side.LEFT);
                            } else {
                                retreatTeam(Team.Side.RIGHT);
                            }
                            return true;
                        case KeyEvent.VK_1:
                            if ( !match.isReverse() ) {
                                retreatVictory(Team.Side.LEFT);
                            } else {
                                retreatVictory(Team.Side.RIGHT);
                            }
                            return true;
                        case KeyEvent.VK_2:
                            if ( !match.isReverse() ) {
                                retreatVictory(Team.Side.RIGHT);
                            } else {
                                retreatVictory(Team.Side.LEFT);
                            }
                            return true;
                    }
                }

                if ( (ke.getKeyCode() == KeyEvent.VK_LEFT ||
                      ke.getKeyCode() == KeyEvent.VK_RIGHT) && match.isEndOfMatch() ) {
                    setVisible(false);
                    windowManager.getDashboardFrame().setVisible(true);
                    match.reset();
                    return true;
                }

                switch ( ke.getKeyCode() ) {
                    case KeyEvent.VK_RIGHT:
                        if ( !match.isReverse() ) {
                            advanceTeam(Team.Side.RIGHT);
                        } else {
                            advanceTeam(Team.Side.LEFT);
                        }
                        return true;
                    case KeyEvent.VK_LEFT:
                        if ( !match.isReverse() ) {
                            advanceTeam(Team.Side.LEFT);
                        } else {
                            advanceTeam(Team.Side.RIGHT);
                        }
                        return true;
                    case KeyEvent.VK_1:
                        if ( !match.isReverse() ) {
                            advanceVictory(Team.Side.LEFT);
                        } else {
                            advanceVictory(Team.Side.RIGHT);
                        }
                        return true;
                    case KeyEvent.VK_2:
                        if ( !match.isReverse() ) {
                            advanceVictory(Team.Side.RIGHT);
                        } else {
                            advanceVictory(Team.Side.LEFT);
                        }
                        return true;
                    case KeyEvent.VK_A:
                        showAdjustmentDialog();
                        return true;
                    case KeyEvent.VK_M:
                        toggleMute();
                        return true;
                    case KeyEvent.VK_N:
                        Actions.NOTHING_BUT_NET.actionPerformed(null);
                        return true;
                    case KeyEvent.VK_H:
                        Actions.SHH.actionPerformed(null);
                        return true;
                    case KeyEvent.VK_T:
                        showSettingsDialog();
                        return true;
                    case KeyEvent.VK_O:
                        Actions.NO_BABY.actionPerformed(null);
                        return true;
                    case KeyEvent.VK_Y:
                        Actions.YEAH_BABY.actionPerformed(null);
                        return true;
                     case KeyEvent.VK_E:
                        Actions.RANDOM_EXCUSE.actionPerformed(null);
                        return true;
                     case KeyEvent.VK_S:
                        Actions.SCORE.actionPerformed(null);
                        return true;
                     case KeyEvent.VK_V:
                        Actions.SERVER.actionPerformed(null);
                        return true;
                     case KeyEvent.VK_SPACE:
                         enableKeyBindings(false);
                         talkText.requestFocusInWindow();
                         return true;
                }
            }
            return false;
        }
    }

    @Override
    public void paint(Graphics g1) {
        super.paint(g1);
        subtitle.paint(g1);
    }

    class ButtonHighlighter extends MouseAdapter {
        @Override
        public void mouseEntered(MouseEvent me) {
            JButton button = (JButton)me.getSource();
            button.setBackground(match.getStyle().getButtonHoverColor());
            button.setForeground(match.getStyle().getBackgroundColor());
        }

        @Override
        public void mouseExited(MouseEvent me) {
            JButton button = (JButton)me.getSource();
            button.setBackground(match.getStyle().getBackgroundColor());
            button.setForeground(match.getStyle().getButtonTextColor());
        }
    }

    private void showAdjustmentDialog() {
        setVisible(false);
        Actions.ADJUST_SCORE.actionPerformed(null);
        setVisible(true);
        refresh();
    }

    private void showSettingsDialog() {
        setVisible(false);
        Actions.ADJUST_SETTINGS.actionPerformed(null);
        setVisible(true);
        refresh();
    }

    private void toggleMute() {
        Actions.MUTE.actionPerformed(null);
        if ( talker.isMute() ) {
            talker.silence();
            subtitle.setText("Sound Off");
        } else {
            subtitle.setText("Sound On");
        }
        subtitle.fade(1000, match.getStyle().getSubtitleFadeTime());
    }

    private void enableKeyBindings(boolean enable) {
        if ( enable && !keyBindingsEnabled ) {
            log.trace("Enabled key bindings");
            KeyboardFocusManager.getCurrentKeyboardFocusManager()
                    .addKeyEventDispatcher(keyboardControl);
            keyBindingsEnabled = true;
        } else if ( !enable && keyBindingsEnabled ) {
            log.trace("Disabled key bindings");
            KeyboardFocusManager.getCurrentKeyboardFocusManager()
                    .removeKeyEventDispatcher(keyboardControl);
            keyBindingsEnabled = false;
        }
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        jEditorPane1 = new javax.swing.JEditorPane();
        leftTeamNameText = new javax.swing.JTextField();
        rightTeamNameText = new javax.swing.JTextField();
        yeahBabyButton = new javax.swing.JButton();
        rightServerText = new javax.swing.JTextField();
        leftServerText = new javax.swing.JTextField();
        leftWinsText = new javax.swing.JTextField();
        rightWinsText = new javax.swing.JTextField();
        leftScoreText = new javax.swing.JTextField();
        rightScoreText = new javax.swing.JTextField();
        noBabyButton = new javax.swing.JButton();
        shhButton = new javax.swing.JButton();
        closeButton = new javax.swing.JButton();
        excuseButton = new javax.swing.JButton();
        talkText = new javax.swing.JTextField();
        settingsButton = new javax.swing.JButton();
        muteButton = new javax.swing.JButton();
        netButton = new javax.swing.JButton();
        scoreButton = new javax.swing.JButton();
        serverButton = new javax.swing.JButton();

        jScrollPane1.setViewportView(jEditorPane1);

        addWindowFocusListener(new java.awt.event.WindowFocusListener() {
            public void windowGainedFocus(java.awt.event.WindowEvent evt) {
                formWindowGainedFocus(evt);
            }
            public void windowLostFocus(java.awt.event.WindowEvent evt) {
                formWindowLostFocus(evt);
            }
        });

        leftTeamNameText.setEditable(false);
        leftTeamNameText.setFont(new java.awt.Font("Inconsolata", 1, 48)); // NOI18N
        leftTeamNameText.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        leftTeamNameText.setText("Home");
        leftTeamNameText.setBorder(null);

        rightTeamNameText.setEditable(false);
        rightTeamNameText.setFont(new java.awt.Font("Inconsolata", 1, 48)); // NOI18N
        rightTeamNameText.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        rightTeamNameText.setText("Away");
        rightTeamNameText.setBorder(null);

        yeahBabyButton.setMnemonic('Y');
        yeahBabyButton.setText("Yeah");
        yeahBabyButton.setActionCommand("Yeah Baby");
        yeahBabyButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        yeahBabyButton.setOpaque(true);

        rightServerText.setEditable(false);
        rightServerText.setFont(new java.awt.Font("Lucida Grande", 1, 48)); // NOI18N
        rightServerText.setHorizontalAlignment(javax.swing.JTextField.LEFT);
        rightServerText.setText("*");
        rightServerText.setBorder(null);

        leftServerText.setEditable(false);
        leftServerText.setFont(new java.awt.Font("Lucida Grande", 1, 48)); // NOI18N
        leftServerText.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        leftServerText.setText("*");
        leftServerText.setBorder(null);

        leftWinsText.setEditable(false);
        leftWinsText.setFont(new java.awt.Font("Inconsolata", 1, 48)); // NOI18N
        leftWinsText.setHorizontalAlignment(javax.swing.JTextField.LEFT);
        leftWinsText.setText("99");
        leftWinsText.setBorder(null);
        leftWinsText.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                leftWinsTextActionPerformed(evt);
            }
        });

        rightWinsText.setEditable(false);
        rightWinsText.setFont(new java.awt.Font("Inconsolata", 1, 48)); // NOI18N
        rightWinsText.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        rightWinsText.setText("99");
        rightWinsText.setBorder(null);

        leftScoreText.setEditable(false);
        leftScoreText.setFont(new java.awt.Font("Inconsolata", 1, 200)); // NOI18N
        leftScoreText.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        leftScoreText.setText("99");
        leftScoreText.setBorder(null);

        rightScoreText.setEditable(false);
        rightScoreText.setFont(new java.awt.Font("Inconsolata", 1, 200)); // NOI18N
        rightScoreText.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        rightScoreText.setText("99");
        rightScoreText.setBorder(null);

        noBabyButton.setMnemonic('O');
        noBabyButton.setText("No");
        noBabyButton.setActionCommand("Yeah Baby");
        noBabyButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        noBabyButton.setOpaque(true);

        shhButton.setMnemonic('H');
        shhButton.setText("Shh");
        shhButton.setActionCommand("Yeah Baby");
        shhButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        shhButton.setOpaque(true);

        closeButton.setText("Close");
        closeButton.setActionCommand("Yeah Baby");
        closeButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        closeButton.setOpaque(true);
        closeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeButtonActionPerformed(evt);
            }
        });

        excuseButton.setMnemonic('E');
        excuseButton.setText("Excuse");
        excuseButton.setActionCommand("Yeah Baby");
        excuseButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        excuseButton.setOpaque(true);

        talkText.setText("Speech");
        talkText.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        talkText.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                talkTextActionPerformed(evt);
            }
        });
        talkText.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                talkTextFocusGained(evt);
            }
            public void focusLost(java.awt.event.FocusEvent evt) {
                talkTextFocusLost(evt);
            }
        });

        settingsButton.setMnemonic('T');
        settingsButton.setText("Settings");
        settingsButton.setActionCommand("Yeah Baby");
        settingsButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        settingsButton.setOpaque(true);

        muteButton.setMnemonic('M');
        muteButton.setText("Mute");
        muteButton.setActionCommand("Yeah Baby");
        muteButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        muteButton.setOpaque(true);

        netButton.setMnemonic('N');
        netButton.setText("Net");
        netButton.setActionCommand("Yeah Baby");
        netButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        netButton.setOpaque(true);

        scoreButton.setMnemonic('S');
        scoreButton.setText("Score");
        scoreButton.setActionCommand("Yeah Baby");
        scoreButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        scoreButton.setOpaque(true);

        serverButton.setMnemonic('V');
        serverButton.setText("Server");
        serverButton.setActionCommand("Yeah Baby");
        serverButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        serverButton.setOpaque(true);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(talkText)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                        .add(closeButton)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .add(muteButton)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(settingsButton)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(excuseButton)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(serverButton)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(scoreButton)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(netButton)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(shhButton)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(noBabyButton)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(yeahBabyButton)
                        .add(4, 4, 4))
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                            .add(layout.createSequentialGroup()
                                .add(leftWinsText, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 57, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(leftTeamNameText, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 149, Short.MAX_VALUE)
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(leftServerText, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 73, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                            .add(leftScoreText))
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                            .add(rightScoreText)
                            .add(layout.createSequentialGroup()
                                .add(rightServerText, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 75, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(rightTeamNameText, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE)
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(rightWinsText, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 44, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))))
                .addContainerGap())
        );

        layout.linkSize(new java.awt.Component[] {leftServerText, leftWinsText, rightServerText, rightWinsText}, org.jdesktop.layout.GroupLayout.HORIZONTAL);

        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                        .add(rightTeamNameText, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 59, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .add(rightWinsText, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 60, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .add(layout.createSequentialGroup()
                        .add(1, 1, 1)
                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                            .add(rightServerText, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 59, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                            .add(leftServerText, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
                    .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                        .add(leftWinsText, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 60, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .add(leftTeamNameText, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 60, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(leftScoreText, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE)
                    .add(rightScoreText))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(closeButton)
                    .add(excuseButton)
                    .add(settingsButton)
                    .add(muteButton)
                    .add(serverButton)
                    .add(scoreButton)
                    .add(netButton)
                    .add(shhButton)
                    .add(noBabyButton)
                    .add(yeahBabyButton))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(talkText, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );

        layout.linkSize(new java.awt.Component[] {leftServerText, leftTeamNameText, leftWinsText, rightServerText, rightTeamNameText, rightWinsText}, org.jdesktop.layout.GroupLayout.VERTICAL);

    }// </editor-fold>//GEN-END:initComponents

    private void formWindowGainedFocus(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowGainedFocus
        enableKeyBindings(true);
    }//GEN-LAST:event_formWindowGainedFocus

    private void formWindowLostFocus(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowLostFocus
        enableKeyBindings(false);
    }//GEN-LAST:event_formWindowLostFocus

    private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
        GraphicsEnvironment.getLocalGraphicsEnvironment()
                .getDefaultScreenDevice().setFullScreenWindow(null);
        this.setVisible(false);
        windowManager.getDashboardFrame().setVisible(true);
    }//GEN-LAST:event_closeButtonActionPerformed

    private void talkTextFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_talkTextFocusGained
        enableKeyBindings(false);
    }//GEN-LAST:event_talkTextFocusGained

    private void talkTextFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_talkTextFocusLost
        enableKeyBindings(true);
    }//GEN-LAST:event_talkTextFocusLost

    private void talkTextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_talkTextActionPerformed
        if ( Strings.isEmpty(talkText.getText()) ) {
            return;
        }
        talker.say(talkText.getText());
        talkText.setText("");
        this.requestFocusInWindow();
    }//GEN-LAST:event_talkTextActionPerformed

    private void leftWinsTextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_leftWinsTextActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_leftWinsTextActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton closeButton;
    private javax.swing.JButton excuseButton;
    private javax.swing.JEditorPane jEditorPane1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextField leftScoreText;
    private javax.swing.JTextField leftServerText;
    private javax.swing.JTextField leftTeamNameText;
    private javax.swing.JTextField leftWinsText;
    private javax.swing.JButton muteButton;
    private javax.swing.JButton netButton;
    private javax.swing.JButton noBabyButton;
    private javax.swing.JTextField rightScoreText;
    private javax.swing.JTextField rightServerText;
    private javax.swing.JTextField rightTeamNameText;
    private javax.swing.JTextField rightWinsText;
    private javax.swing.JButton scoreButton;
    private javax.swing.JButton serverButton;
    private javax.swing.JButton settingsButton;
    private javax.swing.JButton shhButton;
    private javax.swing.JTextField talkText;
    private javax.swing.JButton yeahBabyButton;
    // End of variables declaration//GEN-END:variables

}


text:
// This file is automatically generated.

package adila.db;

/*
 * Samsung Galaxy Core 2
 *
 * DEVICE: kanas3gcmcc
 * MODEL: SM-G3558
 */
final class kanas3gcmcc {
    public static final String DATA = "Samsung|Galaxy Core 2|";
}

redpajama_set_name: RedPajamaGithub


text:
/**
 * @file doxytest.h
 * Write description of source file here for dOxygen.
 *
 * @brief Can use "brief" tag to explicitly generate comments for file documentation.
 *
 */

///  Single line comment for dOxygen.

/**
   Write description of function here.
   The function should follow these comments.
   Use of "brief" tag is optional. (no point to it)

   The function arguments listed with "param" will be compared
   to the declaration and verified.

   @param[in]     inArg1 Description of first function argument.
   @param[out]    outArg2 Description of second function argument.
   @param[in,out] inoutArg3 Description of third function argument.
   @return Description of returned value.
 */

#ifndef __DOXYTEST_H_
#define __DOXYTEST_H_

class doxytest {
public:
    doxytest();
    virtual ~doxytest();
    ///comments on function1 while declaring it
    int function1(int inArg1, int& outArg2, int& inoutArg3);
};

/** Comments on C++ doxytest::function1 while defining it
 */
int doxytest::function1(int _inArg1,/**< Comment on variable goes here. */
        int& _outArg2, /**< Comment on variable goes here. */
        int& _inoutArg3)
{

    /// Single line comment for dOxygen.
    return 0;
}

#endif /* __DOXYTEST_H_ */


text:
#include "priority_buffer_queue.h"

#define XCAM_PRIORITY_BUFFER_FIXED_DELAY 6

namespace XCam {

bool
PriorityBuffer::priority_less_than (const PriorityBuffer& buf) const
{
    int32_t result =
        ((int32_t)(buf.seq_num - this->seq_num) * XCAM_PRIORITY_BUFFER_FIXED_DELAY +
         (int32_t)(buf.rank - this->rank));
    if (result == 0) {
        return (int32_t)(buf.seq_num - this->seq_num) > 0;
    }
    return result > 0;
}

bool
PriorityBufferQueue::push_priority_buf (const SmartPtr<PriorityBuffer> &buf)
{
    XCAM_ASSERT (buf.ptr ());
    SmartLock lock (_mutex);

    ObjList::iterator iter = _obj_list.begin ();

    for (; iter != _obj_list.end (); ++iter) {
        SmartPtr<PriorityBuffer> &current = *iter;
        XCAM_ASSERT (current.ptr ());
        if (buf->priority_less_than (*current.ptr()))
            break;
    }

    _obj_list.insert (iter, buf);
    _new_obj_cond.signal ();
    return true;
}

};


text:
import Row from './row';
import Col from './col';
export { Row, Col };


text:
local log					= require("hs.logger").new("text")

local utf16LE				= require("cp.utf16.le")
local utf16BE				= require("cp.utf16.be")
local protect				= require("cp.protect")

local utf8char, utf8codepoint, utf8codes, utf8len, utf8offset = utf8.char, utf8.codepoint, utf8.codes, utf8.len, utf8.offset
local utf16LEchar, utf16LEcodepoint, utf16LEcodes, utf16LElen, utf16LEoffset = utf16LE.char, utf16LE.codepoint, utf16LE.codes, utf16LE.len, utf16LE.offset
local utf16BEchar, utf16BEcodepoint, utf16BEcodes, utf16BElen, utf16BEoffset = utf16BE.char, utf16BE.codepoint, utf16BE.codes, utf16BE.len, utf16BE.offset
local unpack				= table.unpack
local floor					= math.floor

-- Loads the 'cp.text.matcher' module on demand, to avoid a dependency loop.
local matcher				= function(...)
	matcher = require("cp.text.matcher")
	return matcher(...)
end

local text = {}

text.mt = {}
text.mt.__index = text.mt

--- cp.text.encoding
--- Constant
--- The list of supported encoding formats:
---  * `utf8`		- UTF-8. The most common format on the web, backwards compatible with ANSI/ASCII.
---  * `utf16le`	- UTF-16 (little-endian). Commonly used in Windows and Mac text files.
---  * `utf16be`	- UTF-16 (big-endian). Alternate 16-bit format, common on Linux and PowerPC-based architectures.
text.encoding = protect {
	utf8	= "utf8",
	utf16le	= "utf16le",
	utf16be	= "utf16be",
}

local decoders = {
	utf8	= utf8codepoint,
	utf16le	= utf16LEcodepoint,
	utf16be	= utf16BEcodepoint,
}

local encoders = {
	utf8	= utf8char,
	utf16le	= utf16LEchar,
	utf16be	= utf16BEchar,
}

local BOM = 0xFEFF
local boms = {
	utf8	= string.char(239, 187, 191),
	utf16le	= string.char(255, 254),
	utf16be = string.char(254, 255),
}

local function startsWith(self, otherString)
	local len = otherString:len()

	if self:len() >= len then
		for i = 1,len do
			if self:byte(i) ~= otherString:byte(i) then return false end
		end
		return true
	end
	return false
end

local function isint(n)
  return n==floor(n)
end

local function constrain(value, min, max)
	if value < min then return min end
	if value > max then return max end
	return value
end

-- gets the 'codes' value for a text value
local function getCodes(text)
	return rawget(text, "codes")
end

-- sets the 'codes' value for a text value.
local function setCodes(text, value)
	rawset(text, "codes", value)
end

--- cp.text.fromString(value[, encoding]) -> text
--- Constructor
--- Returns a new `text` instance representing the string value of the specified value. If no encoding is specified,
--- it will attempt to determine the encoding from a leading Byte-Order Marker (BOM). If none is present, it defaults to UTF-8.
---
--- Parameters:
---  * `value`		- The value to turn into a unicode text instance.
---  * `encoding`	- One of the falues from `text.encoding`: `utf8`, `utf16le`, or `utf16be`. Defaults to `utf8`.
---
--- Returns:
---  * A new `text` instance.
---
--- Notes:
---  * Calling `text(value)` is the same as calling `text.fromString(value, text.encoding.utf8)`, so simple text can be initialized via `local x = text "foo"` when the `.lua` file's encoding is UTF-8.
function text.fromString(value, encoding)
	local start = 1
	value = tostring(value)
	if not encoding then
		-- first, check if there are any BOMs
		for enc,bom in pairs(boms) do
			if startsWith(value, bom) then
				encoding = enc
				start = start + bom:len()
				break
			end
		end
		encoding = encoding or text.encoding.utf8
	end

	local decoder = decoders[encoding]
	if not decoder then
		error(string.format("unsupported encoding: %s", encoding))
	end
	return text.fromCodepoints({decoder(value, start, -1)})
end

--- cp.text.fromCodepoints(codepoints[, i[, j]]) -> text
--- Constructor
--- Returns a new `text` instance representing the specified array of codepoints. Since `i` and `j` default to the first
--- and last indexes of the array, simply passing in the array will convert all codepoints in that array.
---
--- Parameters:
---  * `codepoints`	- The array of codepoint integers.
---  * `i`			- The starting index to read from codepoints. Defaults to `1`.
---  * `j`			- The ending index to read from codepoints. Default to `-1`.
---
--- Returns:
---  * A new `text` instance.
---
--- Notes:
---  * You can use a *negative* value for `i` and `j`. If so, it will count back from then end of the `codepoints` array.
---  * If the codepoint array begins with a Byte-Order Marker (BOM), the BOM is skipped in the resulting text.
function text.fromCodepoints(codepoints, i, j)
	local result = {}
	local len = #codepoints

	if len > 0 then
		i = i or 1
		j = j or -1
		if type(i) ~= "number" then
			error("bad argument #2 (integer expected, got "..type(i)..")")
		end
		if type(j) ~= "number" then
			error("bad argument #3 (integer expected, got "..type(i)..")")
		end
		if not isint(i) then
			error(string.format("bad argument #2 (number has no integer representation: %s)", i))
		end
		if not isint(j) then
			error(string.format("bad argument #3 (number has no integer representation: %s)", j))
		end

		if i < 0 then i = len + 1 + i end
		if j < 0 then j = len + 1 + j end

		i = constrain(i, 1, len+1)
		j = constrain(j, 0, len)

		if codepoints[i] == BOM then
			i = i+1
		end

		for x = i,j do
			local cp = codepoints[x]
			if type(cp) ~= "number" then
				error("bad argument #1 for 'fromCodepoints (integer expected, got "..type(cp).." for codepoint #"..x..")")
			end
			result[x-i+1] = cp
		end
	end

	local o = {}
	setmetatable(o, text.mt)
	setCodes(o, result)
	return o
end

--- cp.text.fromFile(path[, encoding]) -> text
--- Constructor
--- Returns a new `text` instance representing the text loaded from the specified path. If no encoding is specified,
--- it will attempt to determine the encoding from a leading Byte-Order Marker (BOM). If none is present, it defaults to UTF-8.
---
--- Parameters:
---  * `value`		- The value to turn into a unicode text instance.
---  * `encoding`	- One of the falues from `text.encoding`: `utf8`, `utf16le`, or `utf16be`. Defaults to `utf8`.
---
--- Returns:
---  * A new `text` instance.
function text.fromFile(path, encoding)
	local file = io.open(path, "r") 		-- r read mode
    if not file then
		error(string.format("Unable to open '%s'", path))
	end
    local content = file:read "*a" 					-- *a or *all reads the whole file
    file:close()

	return text.fromString(content, encoding)
end

--- cp.text.char(...) -> text
--- Constructor
--- Returns the list of one or more codepoint items into a text value, concatenating the results.
---
--- Parameters:
---  * `...`	- The list of codepoint integers.
---
--- Returns:
---  * The `cp.text` value for the list of codepoint values.
function text.char(...)
	return text.fromCodepoints(pack(...))
end

--- cp.text.is(value) -> boolean
--- Function
--- Checks if the provided value is a `text` instance.
---
--- Parameters:
---  * `value`	- The value to check
---
--- Returns:
---  * `true` if the value is a `text` instance.
function text.is(value)
	return value and getmetatable(value) == text.mt
end

--- cp.text:sub(i [, j]) -> cp.text
--- Method
--- Returns the substring of this text that starts at `i` and continues until `j`; `i` and `j` can be negative.
--- If `j` is absent, then it is assumed to be equal to `-1` (which is the same as the string length).
--- In particular, the call `cp.text:sub(1,j)` returns a prefix of `s` with length `j`, and `cp.text:sub(-i)` (for a positive `i`) returns a suffix of s with length i.
function text.mt:sub(i, j)
	j = j or -1
	return text.fromCodepoints(getCodes(self), i, j)
end

--- cp.text:find(pattern [, init [, plain]])
--- Method
--- Looks for the first match of pattern in the string `value`. If it finds a match, then find returns the indices of `value` where this occurrence starts and ends; otherwise, it returns `nil`. A third, optional numerical argument `init` specifies where to start the search; its default value is `1` and can be negative. A value of `true` as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain "find substring" operation, with no characters in pattern being considered "magic". Note that if plain is given, then `init` must be given as well.
---
--- If the pattern has captures, then in a successful match the captured values are also returned, after the two indices.
---
--- Preferences:
---  * `pattern`		- The pattern to find.
---  * `init`			- The index to start matching from. Defaults to `1`.
---  * `plain`			- If `true`, the pattern is treated as plain text.
---
--- Returns:
---  * the start index, the end index, followed by any captures
function text.mt:find(pattern, init, plain)
	return matcher(pattern):find(self, init, plain)
end

--- cp.text:match(pattern[, start]) -> ...
--- Method
--- Looks for the first match of the `pattern` in the text value. If it finds one, then match returns the captures from the pattern; otherwise it returns `nil`. If pattern specifies no captures, then the whole match is returned. A third, optional numerical argument `init` specifies where to start the search; its default value is `1` and can be negative.
---
--- Parameters:
---  * `pattern`	- The text pattern to process.
---  * `start`		- If specified, indicates the starting position to process from. Defaults to `1`.
---
--- Returns:
---  * The capture results, the whole match, or `nil`.
function text.mt:match(pattern, start)
	return matcher(pattern):match(self, start)
end

--- cp.text.matcher:gmatch(pattern[, start]) -> function
--- Method
--- Returns an iterator function that, each time it is called, returns the next captures from pattern over string s. If pattern specifies no captures, then the whole match is produced in each call.
---
--- Parameters:
---  * `pattern`		- The `cp.text` value to process.
---
--- Returns:
---  * The iterator function.
function text.mt:gmatch(pattern, all)
	return matcher(pattern):gmatch(self, all)
end

--- cp.text.matcher:gsub(value, repl, limit) -> text, number
--- Method
--- Returns a copy of `value` in which all (or the first `n`, if given) occurrences of the pattern have been replaced by a replacement string specified by `repl`, which can be text, a string, a table, or a function. gsub also returns, as its second value, the total number of matches that occurred.
---
--- Parameters:
---  * `value`	- The text or string value to process.
---  * `repl`	- The replacement text/string/table/function
---  * `limit`	- The maximum number of times to do the replacement. Defaults to unlimited.
---
--- Returns:
---  * `text`	- The text value with replacements.
---  * `number`	- The number of matches that occurred.
---
--- Notes:
---  * If repl is text or a string, then its value is used for replacement. The character `%` works as an escape character: any sequence in repl of the form `%n`, with `n` between `1` and `9`, stands for the value of the `n`-th captured substring (see below). The sequence `%0` stands for the whole match. The sequence `%%` stands for a single `%`.
---  * If `repl` is a table, then the table is queried for every match, using the first capture as the key; if the pattern specifies no captures, then the whole match is used as the key.
---  * If `repl` is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, in order; if the pattern specifies no captures, then the whole match is passed as a sole argument.
---  * If the value returned by the table query or by the function call is a string or a number, then it is used as the replacement string; otherwise, if it is `false` or `nil`, then there is no replacement (that is, the original match is kept in the string).
function text.mt:gsub(pattern, repl, limit)
	return matcher(pattern):gsub(self, repl, limit)
end

-- provides access to the internal codes array
function text.mt:__index(key)
	if type(key) == "number" then
		local codes = getCodes(self)
		return codes[key]
	elseif key ~= codesKey then
		return rawget(text.mt, key)
	end
	return nil
end

-- prevents codes getting updated directly.
function text.mt:__newindex(k, v)
	error("read-only text value", 2)
end

function text.mt:__len()
	local codes = getCodes(self)
	return #codes
end

--- cp.text:len() -> number
--- Method
--- Returns the number of codepoints in the text.
---
--- Parameters:
---  * None
---
--- Returns:
---  * The number of codepoints.
text.mt.len = text.mt.__len

-- concatenates the left and right values into a single text value.
function text.mt.__concat(left, right)
	return text.fromString(tostring(left) .. tostring(right), text.encoding.utf8)
end

--- cp.text:encode([encoding]) -> string
--- Method
--- Returns the text as an encoded `string` value.
---
--- Parameters:
---  * `encoding`	- The encoding to use when converting. Defaults to `cp.text.encoding.utf8`.
--
-- Returns:
--  * The `string` version of the `cp.text` value with the specified encoding..
function text.mt:encode(encoding)
	encoding = encoding or text.encoding.utf8
	local encoder = encoders[encoding]
	if not encoder then
		error(string.format("Unsupported encoding: %s", encoding))
	end
	return encoder(unpack(self))
end

-- cp.text:__tostring() -> string
-- Method
-- Returns the text as an `string` value encoded as UTF-8.
--
-- Parameters:
--  * None
--
-- Returns:
--  * The `string` version of the `cp.text` value.
function text.mt:__tostring()
	return self:encode(text.encoding.utf8)
end

-- cp.text:__eq(other) -> boolean
-- Method
-- Checks if `other` is a `cp.text` instance, and if so, all codepoints are present in the same order.
--
-- Parameters:
--  * `other`	- The other value to compare to.
--
-- Returns:
--  * `true` if `other` is a `cp.text` and all codepoints are present in the same order.
function text.mt:__eq(other)
	if text.is(other) then
		local localCodes, otherCodes = getCodes(self), getCodes(other)
		local len = #localCodes
		if len == #otherCodes then
			for i = 1,len do
				if localCodes[i] ~= otherCodes[i] then
					return false
				end
			end
			return true
		end
	end
	return false
end

function text.__call(_, ...)
	return text.fromString(..., text.encoding.utf8)
end

return setmetatable(text, text)


text:
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle 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 3 of the License, or
// (at your option) any later version.
//
// Moodle 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 Moodle.  If not, see <http://www.gnu.org/licenses/>.

$string['actions'] = 'Actions';
$string['activate'] = 'Enable access';
$string['activatesuccess'] = 'Access to the badges was successfully enabled.';
$string['addbadgecriteria'] = 'Add badge criteria';
$string['addcriteria'] = 'Add criteria';
$string['addcriteriatext'] = 'To start adding criteria, please select one of the options from the drop-down menu.';
$string['addcourse'] = 'Add courses';
$string['addcourse_help'] = 'Select all courses that should be added to this badge requirement. Hold CTRL key to select multiple items.';
$string['addtobackpack'] = 'Add to backpack';
$string['adminonly'] = 'This page is restricted to site administrators only.';
$string['after'] = 'after the date of issue.';
$string['aggregationmethod'] = 'Aggregation method';
$string['all'] = 'All';
$string['allmethod'] = 'All of the selected conditions are met';
$string['allmethodactivity'] = 'All of the selected activities are complete';
$string['allmethodcourseset'] = 'All of the selected courses are complete';
$string['allmethodmanual'] = 'All of the selected roles award the badge';
$string['allmethodprofile'] = 'All of the selected profile fields have been completed';
$string['allowcoursebadges'] = 'Enable course badges';
$string['allowcoursebadges_desc'] = 'Allow badges to be created and awarded in the course context.';
$string['allowexternalbackpack'] = 'Enable connection to external backpacks';
$string['allowexternalbackpack_desc'] = 'Allow users to set up connections and display badges from their external backpack providers.

Note: It is recommended to leave this option disabled if the website cannot be accessed from the Internet (e.g. because of the firewall).';
$string['any'] = 'Any';
$string['anymethod'] = 'Any of the selected conditions is met';
$string['anymethodactivity'] = 'Any of the selected activities is complete';
$string['anymethodcourseset'] = 'Any of the selected courses is complete';
$string['anymethodmanual'] = 'Any of the selected roles awards the badge';
$string['anymethodprofile'] = 'Any of the selected profile fields has been completed';
$string['archivebadge'] = 'Would you like to delete badge \'{$a}\', but keep existing issued badges?';
$string['archiveconfirm'] = 'Delete and keep existing issued badges';
$string['archivehelp'] = '
This option means that the badge will be marked as "retired" and will no longer appear in the list of badges. Users will no longer be able to earn this badge, however existing badge recipients will still be able to display this badge on their profile page and push it to their external backpacks.

If you would like your users to retain access to the earned badges it is important to select this option instead of fully deleting badges.
';
$string['attachment'] = 'Attach badge to message';
$string['attachment_help'] = 'If enabled, an issued badge file will be attached to the recipient\'s email for download. (Attachments must be enabled in Site administration > Plugins > Message outputs > Email to use this option.)';
$string['award'] = 'Award badge';
$string['awardedtoyou'] = 'Issued to me';
$string['awardoncron'] = 'Access to the badges was successfully enabled. Too many users can instantly earn this badge. To ensure site performance, this action will take some time to process.';
$string['awards'] = 'Recipients';
$string['backpackavailability'] = 'External badge verification';
$string['backpackavailability_help'] = 'For badge recipients to be able to prove they earned their badges from you, an external backpack service should be able to access your site and verify badges issued from it. Your site does not currently appear to be accessible, which means that badges you have already issued or will issue in the future cannot be verified.

**Why am I seeing this message?**

It may be that your firewall prevents access from users outside your network, your site is password protected, or you are running the site on a computer that is not available from the Internet (such as a local development machine).

**Is this a problem?**

You should fix this issue on any production site where you are planning to issue badges, otherwise the recipients will not be able to prove they earned their badges from you. If your site is not yet live you can create and issue test badges, as long as the site is accessible before you go live.

**What if I can\'t make my whole site publicly accessible?**

The only URL required for verification is [your-site-url]/badges/assertion.php so if you are able to modify your firewall to allow external access to that file, badge verification will still work.';
$string['backpackbadges'] = 'You have {$a->totalbadges} badge(s) displayed from {$a->totalcollections} collection(s). Change backpack settings.';
$string['backpackconnection'] = 'Backpack connection';
$string['backpackconnection_help'] = 'This page allows you to set up connection to an external backpack provider. Connecting to a backpack lets you display external badges within this site and push badges earned here to your backpack.

Currently, only Mozilla OpenBadges Backpack is supported. You need to sign up for a backpack service before trying to set up backpack connection on this page.';
$string['backpackdetails'] = 'Backpack settings';
$string['backpackemail'] = 'Email address';
$string['backpackemail_help'] = 'The email address associated with your backpack. While you are connected, any badges earned on this site will be associated with this email address.';
$string['personaconnection'] = 'Sign in with your email';
$string['personaconnection_help'] = 'Persona is a system for identifying yourself across the web, using an email address that you own. The Open Badges backpack uses Persona as a login system, so to be able to connect to a backpack you will need a Persona account.

For more information about Persona visit https://login.persona.org/about.';
$string['backpackimport'] = 'Badge import settings';
$string['backpackimport_help'] = 'After the backpack connection is successfully established, badges from your backpack can be displayed on your badges page and your profile page.

In this area, you can select collections of badges from your backpack that you would like to display in your profile.';
$string['badges'] = 'Badges';
$string['badgedetails'] = 'Badge details';
$string['badgeimage'] = 'Image';
$string['badgeimage_help'] = 'This is an image that will be used when this badge is issued.

To add a new image, browse and select an image (in JPG or PNG format) then click "Save changes". The image will be cropped to a square and resized to match badge image requirements. ';

$string['badgeprivacysetting'] = 'Badge privacy settings';
$string['badgeprivacysetting_help'] = 'Badges you earn can be displayed on your account profile page. This setting allows you to automatically set the visibility of the newly earned badges.

You can still control individual badge privacy settings on your badges page.';
$string['badgeprivacysetting_str'] = 'Automatically show badges I earn on my profile page';
$string['badgesalt'] = 'Salt for hashing the recipient\'s email address';
$string['badgesalt_desc'] = 'Using a hash allows backpack services to confirm the badge earner without having to expose their email address. This setting should only use numbers and letters.

Note: For recipient verification purposes, please avoid changing this setting once you start issuing badges.';
$string['badgesdisabled'] = 'Badges are not enabled on this site.';
$string['badgesearned'] = 'Number of badges earned: {$a}';
$string['badgesettings'] = 'Badges settings';
$string['badgestatus_0'] = 'Not available to users';
$string['badgestatus_1'] = 'Available to users';
$string['badgestatus_2'] = 'Not available to users';
$string['badgestatus_3'] = 'Available to users';
$string['badgestatus_4'] = 'Archived';
$string['badgestoearn'] = 'Number of badges available: {$a}';
$string['badgesview'] = 'Course badges';
$string['badgeurl'] = 'Issued badge link';
$string['bawards'] = 'Recipients ({$a})';
$string['bcriteria'] = 'Criteria';
$string['bdetails'] = 'Edit details';
$string['bmessage'] = 'Message';
$string['boverview'] = 'Overview';
$string['bydate'] = ' complete by';
$string['clearsettings'] = 'Clear settings';
$string['completionnotenabled'] = 'Course completion is not enabled for this course, so it cannot be included in badge criteria. Course completion may be enabled in the course settings.';
$string['completioninfo'] = 'This badge was issued for completing: ';
$string['configenablebadges'] = 'When enabled, this feature lets you create badges and award them to site users.';
$string['configuremessage'] = 'Badge message';
$string['connect'] = 'Connect';
$string['connected'] = 'Connected';
$string['connecting'] = 'Connecting...';
$string['contact'] = 'Contact';
$string['contact_help'] = 'An email address associated with the badge issuer.';
$string['copyof'] = 'Copy of {$a}';
$string['coursebadgesdisabled'] = 'Course badges are not enabled on this site.';
$string['coursecompletion'] = 'Users must complete this course.';
$string['coursebadges'] = 'Badges';
$string['create'] = 'New badge';
$string['createbutton'] = 'Create badge';
$string['creatorbody'] = '
{$a->user} has completed all badge requirements and has been awarded the badge. View issued badge at {$a->link}
';
$string['creatorsubject'] = '\'{$a}\' has been awarded!';
$string['criteriasummary'] = 'Criteria summary';
$string['criteriacreated'] = 'Badge criteria successfully created';
$string['criteriadeleted'] = 'Badge criteria successfully deleted';
$string['criteriaupdated'] = 'Badge criteria successfully updated';
$string['criteria_descr'] = 'Users are awarded this badge when they complete the following requirement:';
$string['criteria_descr_bydate'] = ' by {$a} ';
$string['criteria_descr_grade'] = ' with minimum grade of {$a} ';
$string['criteria_descr_short0'] = 'Complete {$a} of: ';
$string['criteria_descr_short1'] = 'Complete {$a} of: ';
$string['criteria_descr_short2'] = 'Awarded by {$a} of: ';
$string['criteria_descr_short4'] = 'Complete the course ';
$string['criteria_descr_short5'] = 'Complete {$a} of: ';
$string['criteria_descr_short6'] = 'Complete {$a} of: ';
$string['criteria_descr_single_short1'] = 'Complete: ';
$string['criteria_descr_single_short2'] = 'Awarded by: ';
$string['criteria_descr_single_short4'] = 'Complete the course ';
$string['criteria_descr_single_short5'] = 'Complete: ';
$string['criteria_descr_single_short6'] = 'Complete: ';
$string['criteria_descr_single_1'] = 'The following activity has to be completed:';
$string['criteria_descr_single_2'] = 'This badge has to be awarded by a user with the following role:';
$string['criteria_descr_single_4'] = 'Users must complete the course';
$string['criteria_descr_single_5'] = 'The following course has to be completed:';
$string['criteria_descr_single_6'] = 'The following user profile field has to be completed:';
$string['criteria_descr_0'] = 'Users are awarded this badge when they complete {$a} of the listed requirements.';
$string['criteria_descr_1'] = '{$a} of the following activities are completed:';
$string['criteria_descr_2'] = 'This badge has to be awarded by the users with {$a} of the following roles:';
$string['criteria_descr_4'] = 'Users must complete the course';
$string['criteria_descr_5'] = '{$a} of the following courses have to be completed:';
$string['criteria_descr_6'] = '{$a} of the following user profile fields have to be completed:';
$string['criteria_0'] = 'This badge is awarded when...';
$string['criteria_1'] = 'Activity completion';
$string['criteria_1_help'] = 'Allows a badge to be awarded to users based on the completion of a set of activities within a course.';
$string['criteria_2'] = 'Manual issue by role';
$string['criteria_2_help'] = 'Allows a badge to be awarded manually by users who have a particular role within the site or course.';
$string['criteria_3'] = 'Social participation';
$string['criteria_3_help'] = 'Social';
$string['criteria_4'] = 'Course completion';
$string['criteria_4_help'] = 'Allows a badge to be awarded to users who have completed the course. This criterion can have additional parameters such as minimum grade and date of course completion.';
$string['criteria_5'] = 'Completing a set of courses';
$string['criteria_5_help'] = 'Allows a badge to be awarded to users who have completed a set of courses. Each course can have additional parameters such as minimum grade and date of course completion. ';
$string['criteria_6'] = 'Profile completion';
$string['criteria_6_help'] = 'Allows a badge to be awarded to users for completing certain fields in their profile. You can select from default and custom profile fields that are available to users. ';
$string['criterror'] = 'Current parameters issues';
$string['criterror_help'] = 'This fieldset shows all parameters that were initially added to this badge requirement but are no longer available. It is recommended that you un-check such parameters to make sure that users can earn this badge in the future.';
$string['currentimage'] = 'Current image';
$string['currentstatus'] = 'Current status: ';
$string['dateawarded'] = 'Date issued';
$string['dateearned'] = 'Date: {$a}';
$string['day'] = 'Day(s)';
$string['deactivate'] = 'Disable access';
$string['deactivatesuccess'] = 'Access to the badges was successfully disabled.';
$string['defaultissuercontact'] = 'Default badge issuer contact details';
$string['defaultissuercontact_desc'] = 'An email address associated with the badge issuer.';
$string['defaultissuername'] = 'Default badge issuer name';
$string['defaultissuername_desc'] = 'Name of the issuing agent or authority.';
$string['delbadge'] = 'Would you like to delete badge \'{$a}\' and remove all existing issued badges?';
$string['delconfirm'] = 'Delete and remove existing issued badges';
$string['deletehelp'] = '
Fully deleting a badge means that all its information and criteria records will be permanently removed. Users who have earned this badge will no longer be able to access it and display it on their profile pages.

Note: Users who have earned this badge and have already pushed it to their external backpack, will still have this badge in their external backpack. However, they will not be able to access criteria and evidence pages linking back to this web site.
';
$string['delcritconfirm'] = 'Are you sure that you want to delete this criterion?';
$string['delparamconfirm'] = 'Are you sure that you want to delete this parameter?';
$string['description'] = 'Description';
$string['disconnect'] = 'Disconnect';
$string['donotaward'] = 'Currently, this badge is not active, so it cannot be awarded to users. If you would like to award this badge, please set its status to active.';
$string['editsettings'] = 'Edit settings';
$string['enablebadges'] = 'Enable badges';
$string['error:backpackdatainvalid'] = 'The data return from the backpack was invalid.';
$string['error:backpackemailnotfound'] = 'The email \'{$a}\' is not associated with a backpack. You need to create a backpack for that account or sign in with another email address.';
$string['error:backpacknotavailable'] = 'Your site is not accessible from the Internet, so any badges issued from this site cannot be verified by external backpack services.';
$string['error:backpackloginfailed'] = 'You could not be connected to an external backpack for the following reason: {$a}';
$string['error:backpackproblem'] = 'There was a problem connecting to your backpack service provider. Please try again later.';
$string['error:badjson'] = 'The connection attempt returned invalid data.';
$string['error:cannotact'] = 'Cannot activate the badge. ';
$string['error:cannotawardbadge'] = 'Cannot award badge to a user.';
$string['error:cannotdeletecriterion'] = 'This criterion cannot be deleted. ';
$string['error:connectionunknownreason'] = 'The connection was unsuccessful but no reason was given.';
$string['error:clone'] = 'Cannot clone the badge.';
$string['error:duplicatename'] = 'Badge with such name already exists in the system.';
$string['error:externalbadgedoesntexist'] = 'Badge not found';
$string['error:guestuseraccess'] = 'You are currently using guest access. To see badges you need to log in with your user account.';
$string['error:invalidbadgeurl'] = 'Invalid badge issuer URL format.';
$string['error:invalidcriteriatype'] = 'Invalid criteria type.';
$string['error:invalidexpiredate'] = 'Expiry date has to be in the future.';
$string['error:invalidexpireperiod'] = 'Expiry period cannot be negative or equal 0.';
$string['error:noactivities'] = 'There are no activities with completion criteria enabled in this course.';
$string['error:noassertion'] = 'No assertion was returned by Persona. You may have closed the dialog before completing the login process.';
$string['error:nocourses'] = 'Course completion is not enabled for any of the courses in this site, so none can be displayed. Course completion may be enabled in the course settings.';
$string['error:nogroups'] = '
There are no public collections of badges available in your backpack.

Only public collections are shown, visit your backpack to create some public collections.
';
$string['error:nopermissiontoview'] = 'You have no permissions to view badge recipients';
$string['error:nosuchbadge'] = 'Badge with id {$a} does not exist.';
$string['error:nosuchcourse'] = 'Warning: This course is no longer available.';
$string['error:nosuchfield'] = 'Warning: This user profile field is no longer available.';
$string['error:nosuchmod'] = 'Warning: This activity is no longer available.';
$string['error:nosuchrole'] = 'Warning: This role is no longer available.';
$string['error:nosuchuser'] = 'User with this email address does not have an account with the current backpack provider.';
$string['error:notifycoursedate'] = 'Warning: Badges associated with course and activity completions will not be issued until the course start date.';
$string['error:parameter'] = 'Warning: At least one parameter should be selected to ensure correct badge issuing workflow.';
$string['error:personaneedsjs'] = 'Currently, Javascript is required to connect to your backpack. If you can, enable Javascript and reload the page.';
$string['error:requesttimeout'] = 'The connection request timed out before it could complete.';
$string['error:requesterror'] = 'The connection request failed (error code {$a}).';
$string['error:save'] = 'Cannot save the badge.';
$string['error:userdeleted'] = '{$a->user} (This user no longer exists in {$a->site})';
$string['eventbadgeawarded'] = 'Badge awarded';
$string['evidence'] = 'Evidence';
$string['existingrecipients'] = 'Existing badge recipients';
$string['expired'] = 'Expired';
$string['expiredate'] = 'This badge expires on {$a}.';
$string['expireddate'] = 'This badge expired on {$a}.';
$string['expireperiod'] = 'This badge expires {$a} day(s) after being issued.';
$string['expireperiodh'] = 'This badge expires {$a} hour(s) after being issued.';
$string['expireperiodm'] = 'This badge expires {$a} minute(s) after being issued.';
$string['expireperiods'] = 'This badge expires {$a} second(s) after being issued.';
$string['expirydate'] = 'Expiry date';
$string['expirydate_help'] = 'Optionally, badges can expire on a specific date, or the date can be calculated based on the date when the badge was issued to a user. ';
$string['externalconnectto'] = 'To display external badges you need to connect to a backpack.';
$string['externalbadges'] = 'My badges from other web sites';
$string['externalbadgesp'] = 'Badges from other web sites:';
$string['externalbadges_help'] = 'This area displays badges from your external backpack.';
$string['fixed'] = 'Fixed date';
$string['hiddenbadge'] = 'Unfortunately, the badge owner has not made this information available.';
$string['issuedbadge'] = 'Issued badge information';
$string['issuancedetails'] = 'Badge expiry';
$string['issuerdetails'] = 'Issuer details';
$string['issuername'] = 'Issuer name';
$string['issuername_help'] = 'Name of the issuing agent or authority.';
$string['issuerurl'] = 'Issuer URL';
$string['localconnectto'] = 'To share these badges outside this web site you need to connect to a backpack.';
$string['localbadges'] = 'My badges from {$a} web site';
$string['localbadgesh'] = 'My badges from this web site';
$string['localbadgesh_help'] = 'All badges earned within this web site by completing courses, course activities, and other requirements.

You can manage your badges here by making them public or private for your profile page.

You can download all of your badges or each badge separately and save them on your computer. Downloaded badges can be added to your external backpack service.';
$string['localbadgesp'] = 'Badges from {$a}:';
$string['makeprivate'] = 'Make private';
$string['makepublic'] = 'Make public';
$string['managebadges'] = 'Manage badges';
$string['message'] = 'Message body';
$string['messagebody'] = '
You have been awarded the badge "%badgename%"!

More information about this badge can be found on the %badgelink% badge information page.

You can manage and download the badge from your {$a} page.
';
$string['messagesubject'] = 'Congratulations! You just earned a badge!';
$string['method'] = 'This criterion is complete when...';
$string['mingrade'] = 'Minimum grade required';
$string['month'] = 'Month(s)';
$string['mybadges'] = 'My badges';
$string['mybackpack'] = 'My backpack settings';
$string['never'] = 'Never';
$string['newbadge'] = 'Add a new badge';
$string['newimage'] = 'New image';
$string['noawards'] = 'This badge has not been earned yet.';
$string['nobackpack'] = 'There is no backpack service connected to this account.
';
$string['nobackpackbadges'] = 'There are no badges in the collections you have selected. Add more collections.';
$string['nobackpackcollections'] = 'No badge collections have been selected. Add collections.';
$string['nobadges'] = 'There are no badges available.';
$string['nocriteria'] = 'Criteria for this badge have not been set up yet.';
$string['noexpiry'] = 'This badge does not have an expiry date.';
$string['noparamstoadd'] = 'There are no additional parameters available to add to this badge requirement.';
$string['notacceptedrole'] = 'Your current role assignment is not among the roles that can manually issue this badge.

If you would like to see users who have already earned this badge, you can visit {$a} page. ';
$string['notconnected'] = 'Not connected';
$string['nothingtoadd'] = 'There are no available criteria to add.';
$string['notification'] = 'Notify badge creator';
$string['notification_help'] = 'This setting manages notifications sent to a badge creator to let them know that the badge has been issued.

The following options are available:

* **NEVER** – Do not send notifications.

* **EVERY TIME** – Send a notification every time this badge is awarded.

* **DAILY** – Send notifications once a day.

* **WEEKLY** – Send notifications once a week.

* **MONTHLY** – Send notifications once a month.';
$string['notifydaily'] = 'Daily';
$string['notifyevery'] = 'Every time';
$string['notifymonthly'] = 'Monthly';
$string['notifyweekly'] = 'Weekly';
$string['numawards'] = 'This badge has been issued to link}">{$a->count} user(s).';
$string['numawardstat'] = 'This badge has been issued {$a} user(s).';
$string['overallcrit'] = 'of the selected criteria are complete.';
$string['potentialrecipients'] = 'Potential badge recipients';
$string['preferences'] = 'Badge preferences';
$string['recipients'] = 'Badge recipients';
$string['recipientdetails'] = 'Recipient details';
$string['recipientidentificationproblem'] = 'Cannot find a recipient of this badge among the existing users.';
$string['recipientvalidationproblem'] = 'Current user cannot be verified as a recipient of this badge.';
$string['relative'] = 'Relative date';
$string['requiredcourse'] = 'At least one course should be added to the courseset criterion.';
$string['reviewbadge'] = 'Changes in badge access';
$string['reviewconfirm'] = '
This will make your badge visible to users and allow them to start earning it.

It is possible that some users already meet this badge\'s criteria and will be issued this badge immediately after you enable it.

Once a badge has been issued it will be locked - certain settings including the criteria and expiry settings can no longer be changed.

Are you sure you want to enable access to the badge \'{$a}\'?
';
$string['save'] = 'Save';
$string['searchname'] = 'Search by name';
$string['selectaward'] = 'Please select the role you would like to use to award this badge: ';
$string['selectgroup_end'] = 'Only public collections are shown, visit your backpack to create more public collections.';
$string['selectgroup_start'] = 'Select collections from your backpack to display on this site:';
$string['selecting'] = 'With selected badges...';
$string['setup'] = 'Set up connection';
$string['signinwithyouremail'] = 'Sign in with your email';
$string['sitebadges'] = 'Site badges';
$string['sitebadges_help'] = 'Site badges can only be awarded to users for site-related activities. These include completing a set of courses or parts of user profiles. Site badges can also be issued manually by one user to another.

Badges for course-related activities must be created at the course level. Course badges can be found under Course Administration > Badges.';
$string['statusmessage_0'] = 'This badge is currently not available to users. Enable access if you want users to earn this badge. ';
$string['statusmessage_1'] = 'This badge is currently available to users. Disable access to make any changes. ';
$string['statusmessage_2'] = 'This badge is currently not available to users, and its criteria are locked. Enable access if you want users to earn this badge. ';
$string['statusmessage_3'] = 'This badge is currently available to users, and its criteria are locked. ';
$string['statusmessage_4'] = 'This badge is currently archived.';
$string['status'] = 'Badge status';
$string['status_help'] = 'Status of a badge determines its behaviour in the system:

* **AVAILABLE** – Means that this badge can be earned by users. While a badge is available to users, its criteria cannot be modified.

* **NOT AVAILABLE** – Means that this badge is not available to users and cannot be earned or manually issued. If such badge has never been issued before, its criteria can be changed.

Once a badge has been issued to at least one user, it automatically becomes **LOCKED**. Locked badges can still be earned by users, but their criteria can no longer be changed. If you need to modify details or criteria of a locked badge, you can duplicate this badge and make all the required changes.

*Why do we lock badges?*

We want to make sure that all users complete the same requirements to earn a badge. Currently, it is not possible to revoke badges. If we allowed badges requirements to be modified all the time, we would most likely end up with users having the same badge for meeting completely different requirements.';
$string['subject'] = 'Message subject';
$string['variablesubstitution'] = 'Variable substitution in messages.';
$string['variablesubstitution_help'] = 'In a badge message, certain variables can be inserted into the subject and/or body of a message so that they will be replaced with real values when the message is sent. The variables should be inserted into the text exactly as they are shown below. The following variables can be used:

%badgename%
: This will be replaced by the badge\'s full name.

%username%
: This will be replaced by the recipient\'s full name.

%badgelink%
: This will be replaced by the public URL with information about the issued badge.';
$string['viewbadge'] = 'View issued badge';
$string['visible'] = 'Visible';
$string['warnexpired'] = ' (This badge has expired!)';
$string['year'] = 'Year(s)';