text:
package co.aikar.commands;

import co.aikar.commands.CommandRouter.RouteSearch;
import co.aikar.commands.annotation.CatchAll;
import co.aikar.commands.annotation.CatchUnknown;
import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Conditions;
import co.aikar.commands.annotation.Default;
import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.HelpCommand;
import co.aikar.commands.annotation.PreCommand;
import co.aikar.commands.annotation.Subcommand;
import co.aikar.commands.annotation.UnknownHandler;
import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Stack;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * A Base command is defined as a command group of related commands.
 * A BaseCommand does not imply nor enforce that they use the same root command.
 *

 * It is up to the end user how to organize their command. you could use 1 base command per
 * command in your application.
 *

 * Optionally (and encouraged), you can use the base command to represent a root command, and
 * then each actionable command is a sub command
 */

public abstract class BaseCommand {

    /**
     * This is a field which contains the magic key in the {@link #subCommands} map for the method to catch any unknown
     * argument to command states.
     */
    static final String CATCHUNKNOWN = "__catchunknown";
    /**
     * This is a field which contains the magic key in the {@link #subCommands} map for the method which is default for the
     * entire base command.
     */
    static final String DEFAULT = "__default";

    /**
     * A map of all the registered commands for this base command, keyed to each potential subcommand to access it.
     */
    final SetMultimap<String, RegisteredCommand> subCommands = HashMultimap.create();
    final Set<BaseCommand> subScopes = new HashSet<>();

    /**
     * A map of flags to pass to Context Resolution for every parameter of the type. This is like an automatic @Flags on each.
     */
    final Map<Class<?>, String> contextFlags = new HashMap<>();

    /**
     * What method was annoated with {@link PreCommand} to execute before commands.
     */
    @Nullable
    private Method preCommandHandler;

    /**
     * What root command the user actually entered to access the currently executing command
     */
    @SuppressWarnings("WeakerAccess")
    private String execLabel;
    /**
     * What subcommand the user actually entered to access the currently executing command
     */
    @SuppressWarnings("WeakerAccess")
    private String execSubcommand;
    /**
     * What arguments the user actually entered after the root command to access the currently executing command
     */
    @SuppressWarnings("WeakerAccess")
    private String[] origArgs;

    /**
     * The manager this is registered to
     */
    CommandManager<?, ?, ?, ?, ?, ?> manager = null;

    /**
     * The command which owns this. This may be null if there are no owners.
     */
    BaseCommand parentCommand;
    Map<String, RootCommand> registeredCommands = new HashMap<>();
    /**
     * The description of the command. This may be null if no description has been provided.
     * Used for help documentation
     */
    @Nullable String description;
    /**
     * The name of the command. This may be null if no name has been provided.
     */
    @Nullable String commandName;
    /**
     * The permission of the command. This may be null if no permission has been provided.
     */
    @Nullable String permission;
    /**
     * The conditions of the command. This may be null if no conditions has been provided.
     */
    @Nullable String conditions;
    /**
     * Identifies if the command has an explicit help command annotated with {@link HelpCommand}
     */
    boolean hasHelpCommand;

    /**
     * The handler of all uncaught exceptions thrown by the user's command implementation.
     */
    private ExceptionHandler exceptionHandler = null;
    /**
     * The last operative context data of this command. This may be null if this command is not currently being executed.
     */
    private final ThreadLocal<CommandOperationContext> lastCommandOperationContext = new ThreadLocal<>();
    /**
     * If a parent exists to this command, and it has  a Subcommand annotation, prefix all subcommands in this class with this
     */
    @Nullable
    private String parentSubcommand;

    /**
     * The permissions of the command.
     */
    private final Set<String> permissions = new HashSet<>();

    public BaseCommand() {
    }

    /**
     * Constructor based defining of commands will be removed in the next version bump.
     *
     * @param cmd
     * @deprecated Please switch to {@link CommandAlias} for defining all root commands.
     */
    @Deprecated
    public BaseCommand(@Nullable String cmd) {
        this.commandName = cmd;
    }

    /**
     * Returns a reference to the last used CommandOperationContext.
     * This method is ThreadLocal, in that it can only be used on a thread that has executed a command
     *
     * @return
     */
    public CommandOperationContext getLastCommandOperationContext() {
        return lastCommandOperationContext.get();
    }

    /**
     * Gets the root command name that the user actually typed
     *
     * @return Name
     */
    public String getExecCommandLabel() {
        return execLabel;
    }

    /**
     * Gets the actual sub command name the user typed
     *
     * @return Name
     */
    public String getExecSubcommand() {
        return execSubcommand;
    }

    /**
     * Gets the actual args in string form the user typed
     *
     * @return Args
     */
    public String[] getOrigArgs() {
        return origArgs;
    }

    /**
     * This should be called whenever the command gets registered.
     * It sets all required fields correctly and injects dependencies.
     *
     * @param manager The manager to register as this command's owner and handler.
     */
    void onRegister(CommandManager manager) {
        onRegister(manager, this.commandName);
    }

    /**
     * This should be called whenever the command gets registered.
     * It sets all required fields correctly and injects dependencies.
     *
     * @param manager The manager to register as this command's owner and handler.
     * @param cmd     The command name to use register with.
     */
    private void onRegister(CommandManager manager, String cmd) {
        manager.injectDependencies(this);
        this.manager = manager;

        final Annotations annotations = manager.getAnnotations();
        final Class<? extends BaseCommand> self = this.getClass();

        String[] cmdAliases = annotations.getAnnotationValues(self, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE | Annotations.NO_EMPTY);

        if (cmd == null && cmdAliases != null) {
            cmd = cmdAliases[0];
        }

        this.commandName = cmd != null ? cmd : self.getSimpleName().toLowerCase(Locale.ENGLISH);
        this.permission = annotations.getAnnotationValue(self, CommandPermission.class, Annotations.REPLACEMENTS);
        this.description = annotations.getAnnotationValue(self, Description.class, Annotations.NO_EMPTY | Annotations.REPLACEMENTS);
        this.parentSubcommand = getParentSubcommand(self);
        this.conditions = annotations.getAnnotationValue(self, Conditions.class, Annotations.REPLACEMENTS | Annotations.NO_EMPTY);

        computePermissions(); // Must be before any subcommands so they can inherit permissions
        registerSubcommands();
        registerSubclasses(cmd);

        if (cmdAliases != null) {
            Set<String> cmdList = new HashSet<>();
            Collections.addAll(cmdList, cmdAliases);
            cmdList.remove(cmd);
            for (String cmdAlias : cmdList) {
                register(cmdAlias, this);
            }
        }

        if (cmd != null) {
            register(cmd, this);
        }
    }

    /**
     * This recursively registers all subclasses of the command as subcommands, if they are of type {@link BaseCommand}.
     *
     * @param cmd The command name of this command.
     */
    private void registerSubclasses(String cmd) {
        for (Class<?> clazz : this.getClass().getDeclaredClasses()) {
            if (BaseCommand.class.isAssignableFrom(clazz)) {
                try {
                    BaseCommand subScope = null;
                    Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
                    for (Constructor<?> declaredConstructor : declaredConstructors) {

                        declaredConstructor.setAccessible(true);
                        Parameter[] parameters = declaredConstructor.getParameters();
                        if (parameters.length == 1) {
                            subScope = (BaseCommand) declaredConstructor.newInstance(this);
                        } else {
                            manager.log(LogLevel.INFO, "Found unusable constructor: " + declaredConstructor.getName() + "(" + Stream.of(parameters).map(p -> p.getType().getSimpleName() + " " + p.getName()).collect(Collectors.joining("<c2>,</c2> ")) + ")");
                        }
                    }
                    if (subScope != null) {
                        subScope.parentCommand = this;
                        this.subScopes.add(subScope);
                        subScope.onRegister(manager, cmd);
                        this.subCommands.putAll(subScope.subCommands);
                        this.registeredCommands.putAll(subScope.registeredCommands);
                    } else {
                        this.manager.log(LogLevel.ERROR, "Could not find a subcommand ctor for " + clazz.getName());
                    }
                } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
                    this.manager.log(LogLevel.ERROR, "Error registering subclass", e);
                }
            }
        }
    }

    /**
     * This registers all subcommands of the command.
     */
    private void registerSubcommands() {
        final Annotations annotations = manager.getAnnotations();
        boolean foundCatchUnknown = false;
        boolean isParentEmpty = parentSubcommand == null || parentSubcommand.isEmpty();
        Set<Method> methods = new LinkedHashSet<>();
        Collections.addAll(methods, this.getClass().getDeclaredMethods());
        Collections.addAll(methods, this.getClass().getMethods());

        for (Method method : methods) {
            method.setAccessible(true);
            String sublist = null;
            String sub = getSubcommandValue(method);
            final String helpCommand = annotations.getAnnotationValue(method, HelpCommand.class, Annotations.NOTHING);
            final String commandAliases = annotations.getAnnotationValue(method, CommandAlias.class, Annotations.NOTHING);

            if (annotations.hasAnnotation(method, Default.class)) {
                if (!isParentEmpty) {
                    sub = parentSubcommand;
                } else {
                    registerSubcommand(method, DEFAULT);
                }
            }

            if (sub != null) {
                sublist = sub;
            } else if (commandAliases != null) {
                sublist = commandAliases;
            } else if (helpCommand != null) {
                sublist = helpCommand;
                hasHelpCommand = true;
            }

            boolean preCommand = annotations.hasAnnotation(method, PreCommand.class);
            boolean hasCatchUnknown = annotations.hasAnnotation(method, CatchUnknown.class) ||
                    annotations.hasAnnotation(method, CatchAll.class) ||
                    annotations.hasAnnotation(method, UnknownHandler.class);

            if (hasCatchUnknown || (!foundCatchUnknown && helpCommand != null)) {
                if (!foundCatchUnknown) {
                    if (hasCatchUnknown) {
                        this.subCommands.get(CATCHUNKNOWN).clear();
                        foundCatchUnknown = true;
                    }
                    registerSubcommand(method, CATCHUNKNOWN);
                } else {
                    ACFUtil.sneaky(new IllegalStateException("Multiple @CatchUnknown/@HelpCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName()));
                }
            } else if (preCommand) {
                if (this.preCommandHandler == null) {
                    this.preCommandHandler = method;
                } else {
                    ACFUtil.sneaky(new IllegalStateException("Multiple @PreCommand commands, duplicate on " + method.getDeclaringClass().getName() + "#" + method.getName()));
                }
            }
            if (Objects.equals(method.getDeclaringClass(), this.getClass()) && sublist != null) {
                registerSubcommand(method, sublist);
            }
        }
    }

    /**
     * This registers all the permissions required to execute this command.
     */
    private void computePermissions() {
        this.permissions.clear();
        if (this.permission != null && !this.permission.isEmpty()) {
            this.permissions.addAll(Arrays.asList(ACFPatterns.COMMA.split(this.permission)));
        }
        if (this.parentCommand != null) {
            this.permissions.addAll(this.parentCommand.getRequiredPermissions());
        }
        this.subCommands.values().forEach(RegisteredCommand::computePermissions);
        this.subScopes.forEach(BaseCommand::computePermissions);
    }

    /**
     * Gets the subcommand name of the method given.
     *
     * @param method The method to check.
     * @return The name of the subcommand. It returns null if the input doesn't have {@link Subcommand} attached.
     */
    private String getSubcommandValue(Method method) {
        final String sub = manager.getAnnotations().getAnnotationValue(method, Subcommand.class, Annotations.NOTHING);
        if (sub == null) {
            return null;
        }
        Class<?> clazz = method.getDeclaringClass();
        String parent = getParentSubcommand(clazz);
        return parent == null || parent.isEmpty() ? sub : parent + " " + sub;
    }

    private String getParentSubcommand(Class<?> clazz) {
        List<String> subList = new ArrayList<>();
        while (clazz != null) {
            String sub = manager.getAnnotations().getAnnotationValue(clazz, Subcommand.class, Annotations.NOTHING);
            if (sub != null) {
                subList.add(sub);
            }
            clazz = clazz.getEnclosingClass();
        }
        Collections.reverse(subList);
        return ACFUtil.join(subList, " ");
    }

    /**
     * Registers the given {@link BaseCommand cmd} as a child of the {@link RootCommand} linked to the name given.
     *
     * @param name Name of the parent to cmd.
     * @param cmd  The {@link BaseCommand} to add as a child to the {@link RootCommand} owned name field.
     */
    private void register(String name, BaseCommand cmd) {
        String nameLower = name.toLowerCase(Locale.ENGLISH);
        RootCommand rootCommand = manager.obtainRootCommand(nameLower);
        rootCommand.addChild(cmd);

        this.registeredCommands.put(nameLower, rootCommand);
    }

    /**
     * Registers the given {@link Method} as a subcommand.
     *
     * @param method     The method to register as a subcommand.
     * @param subCommand The subcommand's name(s).
     */
    private void registerSubcommand(Method method, String subCommand) {
        subCommand = manager.getCommandReplacements().replace(subCommand.toLowerCase(Locale.ENGLISH));
        final String[] subCommandParts = ACFPatterns.SPACE.split(subCommand);
        // Must run getSubcommandPossibility BEFORE we rewrite it just after this.
        Set<String> cmdList = getSubCommandPossibilityList(subCommandParts);

        // Strip pipes off for auto complete addition
        for (int i = 0; i < subCommandParts.length; i++) {
            String[] split = ACFPatterns.PIPE.split(subCommandParts[i]);
            if (split.length == 0 || split[0].isEmpty()) {
                throw new IllegalArgumentException("Invalid @Subcommand configuration for " + method.getName() + " - parts can not start with | or be empty");
            }
            subCommandParts[i] = split[0];
        }
        String prefSubCommand = ApacheCommonsLangUtil.join(subCommandParts, " ");
        final String[] aliasNames = manager.getAnnotations().getAnnotationValues(method, CommandAlias.class, Annotations.REPLACEMENTS | Annotations.LOWERCASE);

        String cmdName = aliasNames != null ? aliasNames[0] : this.commandName + " ";
        RegisteredCommand cmd = manager.createRegisteredCommand(this, cmdName, method, prefSubCommand);

        for (String subcmd : cmdList) {
            subCommands.put(subcmd, cmd);
        }
        cmd.addSubcommands(cmdList);

        if (aliasNames != null) {
            for (String name : aliasNames) {
                register(name, new ForwardingCommand(this, cmd, subCommandParts));
            }
        }
    }

    /**
     * Takes a string like "foo|bar baz|qux" and generates a list of
     * - foo baz
     * - foo qux
     * - bar baz
     * - bar qux
     *

     * For every possible sub command combination
     *
     * @param subCommandParts
     * @return List of all sub command possibilities
     */
    private static Set<String> getSubCommandPossibilityList(String[] subCommandParts) {
        int i = 0;
        Set<String> current = null;
        while (true) {
            Set<String> newList = new HashSet<>();

            if (i < subCommandParts.length) {
                for (String s1 : ACFPatterns.PIPE.split(subCommandParts[i])) {
                    if (current != null) {
                        newList.addAll(current.stream().map(s -> s + " " + s1).collect(Collectors.toList()));
                    } else {
                        newList.add(s1);
                    }
                }
            }

            if (i + 1 < subCommandParts.length) {
                current = newList;
                i = i + 1;
                continue;
            }

            return newList;
        }
    }

    void execute(CommandIssuer issuer, CommandRouter.CommandRouteResult command) {
        try {
            CommandOperationContext commandContext = preCommandOperation(issuer, command.commandLabel, command.args, false);
            execSubcommand = command.subcommand;
            executeCommand(commandContext, issuer, command.args, command.cmd);
        } finally {
            postCommandOperation();
        }
    }

    /**
     * This is ran after any command operation has been performed.
     */
    private void postCommandOperation() {
        CommandManager.commandOperationContext.get().pop();
        lastCommandOperationContext.set(null);
        execSubcommand = null;
        execLabel = null;
        origArgs = new String[]{};
    }

    /**
     * This is ran before any command operation has been performed.
     *
     * @param issuer       The user who executed the command.
     * @param commandLabel The label the user used to execute the command. This is not the command name, but their input.
     *                     When there is multiple aliases, this is which alias was used
     * @param args         The arguments passed to the command when executing it.
     * @param isAsync      Whether the command is executed off of the main thread.
     * @return The context which is being registered to the {@link CommandManager}'s {@link
     * CommandManager#commandOperationContext thread local stack}.
     */
    private CommandOperationContext preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync) {
        Stack<CommandOperationContext> contexts = CommandManager.commandOperationContext.get();
        CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args, isAsync);
        contexts.push(context);
        lastCommandOperationContext.set(context);
        execSubcommand = null;
        execLabel = commandLabel;
        origArgs = args;
        return context;
    }

    /**
     * Gets the current command issuer.
     *
     * @return The current command issuer.
     */
    public CommandIssuer getCurrentCommandIssuer() {
        return CommandManager.getCurrentCommandIssuer();
    }

    /**
     * Gets the current command manager.
     *
     * @return The current command manager.
     */
    public CommandManager getCurrentCommandManager() {
        return CommandManager.getCurrentCommandManager();
    }

    private void executeCommand(CommandOperationContext commandOperationContext,
                                CommandIssuer issuer, String[] args, RegisteredCommand cmd) {
        if (cmd.hasPermission(issuer)) {
            commandOperationContext.setRegisteredCommand(cmd);
            if (checkPrecommand(commandOperationContext, cmd, issuer, args)) {
                return;
            }
            List<String> sargs = Arrays.asList(args);
            cmd.invoke(issuer, sargs, commandOperationContext);
        } else {
            issuer.sendMessage(MessageType.ERROR, MessageKeys.PERMISSION_DENIED);
        }
    }

    /**
     * Please use command conditions for restricting execution
     *
     * @param issuer
     * @param cmd
     * @return
     * @deprecated See {@link CommandConditions}
     */
    @SuppressWarnings("DeprecatedIsStillUsed")
    @Deprecated
    public boolean canExecute(CommandIssuer issuer, RegisteredCommand<?> cmd) {
        return true;
    }

    /**
     * Gets tab completed data from the given command from the user.
     *
     * @param issuer       The user who executed the tabcomplete.
     * @param commandLabel The label which is being used by the user.
     * @param args         The arguments the user has typed so far.
     * @return All possibilities in the tab complete.
     */
    public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args) {
        return tabComplete(issuer, commandLabel, args, false);
    }

    /**
     * Gets the tab complete suggestions from a given command. This will automatically find anything
     * which is valid for the specified command through the command's implementation.
     *
     * @param issuer       The issuer of the command.
     * @param commandLabel The command name as entered by the user instead of the ACF registered name.
     * @param args         All arguments entered by the user.
     * @param isAsync      Whether this is run off of the main thread.
     * @return The possibilities to tab complete in no particular order.
     */
    @SuppressWarnings("WeakerAccess")
    public List<String> tabComplete(CommandIssuer issuer, String commandLabel, String[] args, boolean isAsync)
            throws IllegalArgumentException {
        return tabComplete(issuer, manager.getRootCommand(commandLabel.toLowerCase(Locale.ENGLISH)), args, isAsync);
    }

    List<String> tabComplete(CommandIssuer issuer, RootCommand rootCommand, String[] args, boolean isAsync)
            throws IllegalArgumentException {
        if (args.length == 0) {
            args = new String[]{""};
        }
        String commandLabel = rootCommand.getCommandName();
        try {
            CommandRouter router = manager.getRouter();

            preCommandOperation(issuer, commandLabel, args, isAsync);

            final RouteSearch search = router.routeCommand(rootCommand, commandLabel, args, true);

            final List<String> cmds = new ArrayList<>();
            if (search != null) {
                for (RegisteredCommand<?> command : search.commands) {
                    cmds.addAll(completeCommand(issuer, command, search.args, commandLabel, isAsync));
                }
            }

            return filterTabComplete(args[args.length - 1], cmds);
        } finally {
            postCommandOperation();
        }
    }

    /**
     * Gets all subcommands which are possible to tabcomplete.
     *
     * @param issuer The command issuer.
     * @param args
     * @return
     */
    List<String> getCommandsForCompletion(CommandIssuer issuer, String[] args) {
        final Set<String> cmds = new HashSet<>();
        final int cmdIndex = Math.max(0, args.length - 1);
        String argString = ApacheCommonsLangUtil.join(args, " ").toLowerCase(Locale.ENGLISH);
        for (Map.Entry<String, RegisteredCommand> entry : subCommands.entries()) {
            final String key = entry.getKey();
            if (key.startsWith(argString) && !isSpecialSubcommand(key)) {
                final RegisteredCommand value = entry.getValue();
                if (!value.hasPermission(issuer) || value.isPrivate) {
                    continue;
                }

                String[] split = ACFPatterns.SPACE.split(value.prefSubCommand);
                cmds.add(split[cmdIndex]);
            }
        }
        return new ArrayList<>(cmds);
    }

    static boolean isSpecialSubcommand(String key) {
        return CATCHUNKNOWN.equals(key) || DEFAULT.equals(key);
    }

    /**
     * Complete a command properly per issuer and input.
     *
     * @param issuer       The user who executed this.
     * @param cmd          The command to be completed.
     * @param args         All arguments given by the user.
     * @param commandLabel The command name the user used.
     * @param isAsync      Whether the command was executed async.
     * @return All results to complete the command.
     */
    private List<String> completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) {
        if (!cmd.hasPermission(issuer) || args.length == 0 || cmd.parameters.length == 0) {
            return Collections.emptyList();
        }

        if (!cmd.parameters[cmd.parameters.length - 1].consumesRest && args.length > cmd.consumeInputResolvers) {
            return Collections.emptyList();
        }

        List<String> cmds = manager.getCommandCompletions().of(cmd, issuer, args, isAsync);
        return filterTabComplete(args[args.length - 1], cmds);
    }

    /**
     * Gets the actual args in string form the user typed
     * This returns a list of all tab complete options which are possible with the given argument and commands.
     *
     * @param arg  Argument which was pressed tab on.
     * @param cmds The possibilities to return.
     * @return All possible options. This may be empty.
     */
    private static List<String> filterTabComplete(String arg, List<String> cmds) {
        return cmds.stream()
                .distinct()
                .filter(cmd -> cmd != null && (arg.isEmpty() || ApacheCommonsLangUtil.startsWithIgnoreCase(cmd, arg)))
                .collect(Collectors.toList());
    }

    /**
     * Executes the precommand and sees whether something is wrong. Ideally, you get false from this.
     *
     * @param commandOperationContext The context to use.
     * @param cmd                     The command executed.
     * @param issuer                  The issuer who executed the command.
     * @param args                    The arguments the issuer provided.
     * @return Whether something went wrong.
     */
    private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) {
        Method pre = this.preCommandHandler;
        if (pre != null) {
            try {
                Class<?>[] types = pre.getParameterTypes();
                Object[] parameters = new Object[pre.getParameterCount()];
                for (int i = 0; i < parameters.length; i++) {
                    Class<?> type = types[i];
                    Object issuerObject = issuer.getIssuer();
                    if (manager.isCommandIssuer(type) && type.isAssignableFrom(issuerObject.getClass())) {
                        parameters[i] = issuerObject;
                    } else if (CommandIssuer.class.isAssignableFrom(type)) {
                        parameters[i] = issuer;
                    } else if (RegisteredCommand.class.isAssignableFrom(type)) {
                        parameters[i] = cmd;
                    } else if (String[].class.isAssignableFrom((type))) {
                        parameters[i] = args;
                    } else {
                        parameters[i] = null;
                    }
                }

                return (boolean) pre.invoke(this, parameters);
            } catch (IllegalAccessException | InvocationTargetException e) {
                this.manager.log(LogLevel.ERROR, "Exception encountered while command pre-processing", e);
            }
        }
        return false;
    }

    /**
     * @deprecated Unstable API
     */
    @Deprecated
    @UnstableAPI
    public CommandHelp getCommandHelp() {
        return manager.generateCommandHelp();
    }

    /**
     * @deprecated Unstable API
     */
    @Deprecated
    @UnstableAPI
    public void showCommandHelp() {
        getCommandHelp().showHelp();
    }

    public void help(Object issuer, String[] args) {
        help(manager.getCommandIssuer(issuer), args);
    }

    public void help(CommandIssuer issuer, String[] args) {
        issuer.sendMessage(MessageType.ERROR, MessageKeys.UNKNOWN_COMMAND);
    }

    public void doHelp(Object issuer, String... args) {
        doHelp(manager.getCommandIssuer(issuer), args);
    }

    public void doHelp(CommandIssuer issuer, String... args) {
        help(issuer, args);
    }

    public void showSyntax(CommandIssuer issuer, RegisteredCommand<?> cmd) {
        issuer.sendMessage(MessageType.SYNTAX, MessageKeys.INVALID_SYNTAX,
                "{command}", manager.getCommandPrefix(issuer) + cmd.command,
                "{syntax}", cmd.getSyntaxText(issuer)
        );
    }

    public boolean hasPermission(Object issuer) {
        return hasPermission(manager.getCommandIssuer(issuer));
    }

    public boolean hasPermission(CommandIssuer issuer) {
        return this.manager.hasPermission(issuer, getRequiredPermissions());
    }

    public Set<String> getRequiredPermissions() {
        return this.permissions;
    }

    public boolean requiresPermission(String permission) {
        return getRequiredPermissions().contains(permission);
    }

    public String getName() {
        return commandName;
    }

    public ExceptionHandler getExceptionHandler() {
        return exceptionHandler;
    }

    public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) {
        this.exceptionHandler = exceptionHandler;
        return this;
    }

    public RegisteredCommand getDefaultRegisteredCommand() {
        return ACFUtil.getFirstElement(this.subCommands.get(DEFAULT));
    }

    public String setContextFlags(Class<?> cls, String flags) {
        return this.contextFlags.put(cls, flags);
    }

    public String getContextFlags(Class<?> cls) {
        return this.contextFlags.get(cls);
    }

    public List<RegisteredCommand> getRegisteredCommands() {
        List<RegisteredCommand> registeredCommands = new ArrayList<>();
        registeredCommands.addAll(this.subCommands.values());
        return registeredCommands;
    }

    protected SetMultimap<String, RegisteredCommand> getSubCommands() {
        return subCommands;
    }
}


text:
package com.alibaba.druid.sql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import org.junit.Assert;
import junit.framework.TestCase;

import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlParameterizedOutputVisitor;
import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleParameterizedOutputVisitor;

public class OnlineSQLTest extends TestCase {

    private String url      = "jdbc:mysql://10.20.129.146/dragoon_v25monitordb_online";
    private String user     = "dragoon";
    private String password = "dragoon";

    public void test_list_sql() throws Exception {
        // reset();

        // 这些中文括号
        // update(7216, "", 4);
        // update(7223, "", 4);
        // update(8387, "", 4);

        // 语法错误
        // update(17018, "", 4); //alarm_type&?
        // update(17841, "", 4); //alarm_type&?
        // update(17845, "", 4); //alarm_type&?
        // update(18247, "", 4); //alarm_type&?
        // update(19469, "", 4); //alarm_type&?
        update(19730, "", 4); // alarm_type&?
        update(20164, "", 4); // alarm_type&?
        update(20386, "", 4); // alarm_type&?
        update(20440, "", 4); // alarm_type&?
        update(21208, "", 4); // alarm_type&?

        // IBATIS NAME
        update(18035, "", 4); // alarm_type&?

        Connection conn = DriverManager.getConnection(url, user, password);

        int count = 0;
        String sql = "SELECT id, value FROM m_sql_const WHERE flag IS NULL LIMIT 100";
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(sql);
        while (rs.next()) {
            int id = rs.getInt(1);
            String value = rs.getString(2);

            if (value.indexOf('(') != -1) {
                update(id, "", 4);
                continue;
            }

            System.out.println(value);
            System.out.println();
            try {
                validateOracle(id, value);
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("id : " + id);
                continue;
            }
            count++;
        }
        rs.close();
        stmt.close();

        System.out.println("COUNT : " + count);

        conn.close();
    }

    void reset() throws SQLException {
        Connection conn = DriverManager.getConnection(url, user, password);

        String sql = "UPDATE m_sql_const SET flag = NULL, value2 = NULL";
        PreparedStatement stmt = conn.prepareStatement(sql);
        stmt.executeUpdate();
        stmt.close();

        conn.close();
    }

    void update(int id, String value2, int flag) throws SQLException {
        Connection conn = DriverManager.getConnection(url, user, password);

        String sql = "UPDATE m_sql_const SET flag = ?, value2 = ? WHERE id = ?";
        PreparedStatement stmt = conn.prepareStatement(sql);
        stmt.setInt(1, flag);
        stmt.setString(2, value2);
        stmt.setInt(3, id);
        stmt.executeUpdate();
        stmt.close();

        conn.close();
    }

    void validate(int id, String sql) throws Exception {
        sql = sql.trim();
        boolean sqlFlag = false;
        String lowerSql = sql.toLowerCase();
        if (lowerSql.startsWith("insert") || lowerSql.startsWith("select") || lowerSql.startsWith("upate")
            || lowerSql.startsWith("delete") || lowerSql.startsWith("create") || lowerSql.startsWith("drop")) {
            sqlFlag = true;
        }

        if (!sqlFlag) {
            update(id, sql, 2);
            return;
        }

        MySqlStatementParser parser = new MySqlStatementParser(sql);
        List<SQLStatement> statementList = parser.parseStatementList();
        SQLStatement statemen = statementList.get(0);

        Assert.assertEquals(1, statementList.size());

        StringBuilder out = new StringBuilder();
        MySqlParameterizedOutputVisitor visitor = new MySqlParameterizedOutputVisitor(out);
        statemen.accept(visitor);

        update(id, out.toString(), 1);
        System.out.println(sql);
        System.out.println(out.toString());
    }

    void validateOracle(int id, String sql) throws Exception {
        sql = sql.trim();
        boolean sqlFlag = false;
        String lowerSql = sql.toLowerCase();
        if (lowerSql.startsWith("insert") || lowerSql.startsWith("select") || lowerSql.startsWith("upate")
            || lowerSql.startsWith("delete") || lowerSql.startsWith("create") || lowerSql.startsWith("drop")) {
            sqlFlag = true;
        }

        if (!sqlFlag) {
            update(id, sql, 2);
            return;
        }

        OracleStatementParser parser = new OracleStatementParser(sql);
        List<SQLStatement> statementList = parser.parseStatementList();
        SQLStatement statemen = statementList.get(0);

        Assert.assertEquals(1, statementList.size());

        StringBuilder out = new StringBuilder();
        OracleParameterizedOutputVisitor visitor = new OracleParameterizedOutputVisitor(out);
        statemen.accept(visitor);

        update(id, out.toString(), 1);
        System.out.println(sql);
        System.out.println(out.toString());
    }
}

redpajama_set_name: RedPajamaGithub


text:
import {LitElement, html} from 'lit';
import {map} from 'lit/directives/map.js';
import {customElement, property} from 'lit/decorators.js';

@customElement('my-element')
export class MyElement extends LitElement {
  @property()
  groceries = ['tea', 'milk', 'honey', 'chocolate'];

  removeItem(item: string) {
    const indexToRemove = this.groceries.indexOf(item);
    this.groceries =
        this.groceries.filter((_, i) => i !== indexToRemove);
  }

  render() {
    return html`
      ${map(this.groceries, (item) =>
        html`<button @click=${() => this.removeItem(item)}>x</button>  ${item}<br>`
      )}
    `;
  }
}


text:
require 'spec_helper'

describe "gws_schedule_plans", type: :feature, dbscope: :example, js: true do
  let(:site) { gws_site }
  let(:now) { Time.zone.now.change(sec: 0) }
  let(:plan) { create(:gws_schedule_plan, start_at: now + 1.hour, end_at: now + 2.hours) }
  let(:show_path) { gws_schedule_plan_path site, plan }

  before do
    ActionMailer::Base.deliveries.clear

    # メール転送を有効にする
    user = gws_user
    user.notice_schedule_user_setting = "notify"
    user.notice_schedule_email_user_setting = "notify"
    user.send_notice_mail_addresses = "#{unique_id}@example.jp"
    user.save!

    login_gws_user
  end

  context "when reminder on schedule plan is cancelled" do
    let(:reminder_condition) do
      { 'user_id' => gws_user.id, 'state' => 'mail', 'interval' => 10, 'interval_type' => 'minutes' }
    end

    before do
      # リマインダーを保存させるために @db_changes が必要なため、`#name` に別の文字列をセットする。
      plan.name = unique_id
      plan.in_reminder_conditions = [ reminder_condition ]
      plan.save!
    end

    it do
      #
      # リマインダーが 1 件登録されているはずなので、確認する
      #
      visit show_path
      expect(Gws::Reminder.count).to eq 1
      within ".gws-addon-reminder" do
        within first('.reminder-conditions tr') do
          selected = I18n.t('gws/reminder.options.notify_state.mail')
          expect(page).to have_select("item[in_reminder_conditions][][state]", selected: selected)
        end
      end

      #
      # リマインダーを解除
      #
      within ".gws-addon-reminder" do
        within first('.reminder-conditions tr') do
          find('button.action-remove').click
        end
        click_on I18n.t('gws/reminder.buttons.register_reminder')
      end

      # 解除できたか確認
      # リマインダーは非同期で解除される。
      expect(page).to have_css('#notice', text: I18n.t('gws/reminder.notification.created'))

      # 解除できたら、ドキュメントは存在しないはず
      expect(Gws::Reminder.count).to eq 0
    end
  end

  context "when `enabled` is given to reminder state" do
    it do
      #
      # リマインダーを登録する
      #
      visit show_path
      within ".gws-addon-reminder" do
        within first('.reminder-conditions tr') do
          select I18n.t('gws/reminder.options.notify_state.enabled'), from: 'item[in_reminder_conditions][][state]'
        end
        click_on I18n.t('gws/reminder.buttons.register_reminder')
      end

      # 登録できたか確認
      # リマインダーは非同期で登録される。
      # capybara は element が存在しない場合、しばらく待機するので、以下の確認は登録を待機する意味もある
      expect(page).to have_css('#notice', text: I18n.t('gws/reminder.notification.created'))

      expect(Gws::Reminder.count).to eq 1
      reminder = Gws::Reminder.first
      expect(reminder.site_id).to eq plan.site_id
      expect(reminder.date).to eq plan.start_at
      expect(reminder.start_at).to eq plan.start_at
      expect(reminder.end_at).to eq plan.end_at
      expect(reminder.notifications.length).to eq 1
      reminder.notifications.first.tap do |notification|
        expect(notification.state).to eq "enabled"
        expect(notification.interval).to eq 10
        expect(notification.interval_type).to eq "minutes"
        expect(notification.notify_at).to eq plan.start_at - notification.interval.minutes
        expect(notification.base_time).to be_blank
        expect(notification.delivered_at).to eq Time.zone.at(0)
      end

      #
      # リマインド日時まで時を進め、通知送信ジョブを実行する
      #
      Timecop.freeze(reminder.notifications.first.notify_at) do
        Gws::Reminder::NotificationJob.bind(site_id: site.id).perform_now
      end
      Job::Log.first.tap do |log|
        expect(log.logs).to include(/INFO -- : .* Started Job/)
        expect(log.logs).to include(/INFO -- : .* Completed Job/)
      end

      reminder.reload
      expect(reminder.notifications.length).to eq 1
      reminder.notifications.first.tap do |notification|
        expect(notification.delivered_at).to eq notification.notify_at
      end

      expect(SS::Notification.all.count).to eq 1
      SS::Notification.all.first.tap do |notice|
        I18n.with_locale(I18n.default_locale) do
          subject = I18n.t(
            "gws/reminder.notification.subject",
            model: I18n.t("mongoid.models.#{reminder.model}"), name: reminder.name
          )
          expect(notice.subject).to eq subject
          expect(notice.member_ids.length).to eq 1
          expect(notice.member_ids).to include(reminder.user_id)
        end
      end

      # スケジュールの通知転送設定を有効にしても、リマインダーには効果なし
      expect(ActionMailer::Base.deliveries.length).to eq 0
    end
  end

  context "when `mail` is given to reminder state" do
    include Gws::Schedule::PlanHelper

    it do
      #
      # リマインダーを登録する
      #
      visit show_path
      within ".gws-addon-reminder" do
        within first('.reminder-conditions tr') do
          select I18n.t('gws/reminder.options.notify_state.mail'), from: 'item[in_reminder_conditions][][state]'
        end
        click_on I18n.t('gws/reminder.buttons.register_reminder')
      end

      # 登録できたか確認
      # リマインダーは非同期で登録される。
      # capybara は element が存在しない場合、しばらく待機するので、以下の確認は登録を待機する意味もある
      expect(page).to have_css('#notice', text: I18n.t('gws/reminder.notification.created'))

      expect(Gws::Reminder.count).to eq 1
      reminder = Gws::Reminder.first
      expect(reminder.site_id).to eq plan.site_id
      expect(reminder.date).to eq plan.start_at
      expect(reminder.start_at).to eq plan.start_at
      expect(reminder.end_at).to eq plan.end_at
      expect(reminder.notifications.length).to eq 1
      reminder.notifications.first.tap do |notification|
        expect(notification.state).to eq "mail"
        expect(notification.interval).to eq 10
        expect(notification.interval_type).to eq "minutes"
        expect(notification.notify_at).to eq plan.start_at - notification.interval.minutes
        expect(notification.base_time).to be_blank
        expect(notification.delivered_at).to eq Time.zone.at(0)
      end

      #
      # リマインド日時まで時を進め、通知送信ジョブを実行する
      #
      Timecop.freeze(reminder.notifications.first.notify_at) do
        Gws::Reminder::NotificationJob.bind(site_id: site.id).perform_now
      end
      Job::Log.first.tap do |log|
        expect(log.logs).to include(/INFO -- : .* Started Job/)
        expect(log.logs).to include(/INFO -- : .* Completed Job/)
      end

      reminder.reload
      expect(reminder.notifications.length).to eq 1
      reminder.notifications.first.tap do |notification|
        expect(notification.delivered_at).to eq notification.notify_at
      end

      # 通知はされていない
      expect(SS::Notification.all.count).to eq 0

      # メールが送られたはず
      expect(ActionMailer::Base.deliveries.length).to eq 1
      ActionMailer::Base.deliveries.first.tap do |mail|
        I18n.with_locale(I18n.default_locale) do
          subject = I18n.t(
            "gws/reminder.notification.subject",
            model: I18n.t("mongoid.models.#{reminder.model}"), name: reminder.name
          )
          expect(mail.subject).to eq subject
          expect(mail.to.length).to eq 1
          expect(mail.to).to include reminder.user.email
          expect(mail.body.multipart?).to be_falsey
          expect(mail.body.raw_source).to include "[#{reminder.item.class.t :name}] #{reminder.item.name}"
          expect(mail.body.raw_source).to include "[#{reminder.item.class.t :term}] #{term(reminder.item)}"
          expect(mail.body.raw_source).to include reminder.user.long_name
        end
      end
    end
  end
end


text:
The following methods are available to Department resources:

|Resource Method|HTTP Request|Description|Module|RBAC|
|---|---|---|---|---|
|[list](Department.md#list)|GET /department/|Get a list of departments at the convention.|core|--|
|[get](Department.md#get)|GET /department/{identifier}|Get details about a given Department.|core|--|
|[deadlines](Department.md#deadlines)|GET /department/{identifier}/deadlines|Get a list of deadlines for a given Department.|core|api.get.deadline.{department}|
|[add_deadline](Department.md#add_deadline)|POST /department/{identifier}/deadline|Add a new deadline.|core|api.post.deadline.{department}|
|[announcements](Department.md#announcements)|GET /department/{identifier}/announcments|Get a list of announcements for a given Department.|core|-|
|[add_announcement](Department.md#add_announcement)|POST /department/{identifier}/announcement|Add a new announcement.|core|api.post.announcement.{department}|
|[staff](Staff.md#department)|GET /department/{identifier}/staff|Get a list of the Staff for the department.|[staff](Staff.md)|api.get.staff|
|[staff list](Staff.md#list)|GET /department/staff/|Get a list of the whole Staff.|[staff](Staff.md)|api.get.staff|

## list
Get a list of departments on the system.

### list Request

```GET /department/```

### list Parameters

The following list parameters are available:

|Parameter|Meaning|Notes|
|---|---|---|
|page|Page token for the list.|Defaults to first page.|
|maxResults|Maximum results in the list|Defaults to 100. The token "all" specifies the full remaining list.|

### list Request Body

Do not supply a request body.

### list Response
A department_entry object resource.

#### department_entry object resource

A department_entry object resource is used when listing departments. Use a department get method to retrieve the full department data.

```
{
	"type":"department_entry",
	"id":{integer},
	"get":{HATEOAS link}
}
```

department_entry object resources have the following available properties:

|Object Property|Value|Description|Includable|
|---|---|---|---|
|type|string|Always `department_entry`|-|
|id|integer|Department ID for this department.|**yes** `department`|
|get|HATEOAS link|A HATEOAS link for the get method on the department|-|

### list Code Samples
Request Sample

```
curl -X GET -H 'Authorization: Bearer e0438d90599b1c4762d12fd03db6311c9ca46729' \
    http://localhost/api/department/?pretty=true
```
Response Sample

```
{
    "type": "department_list",
    "data": {
        {
            "type": "department_entry",
            "id": 100,
            "get": "http:\/\/localhost\/api\/department\/100"
        },
        {
            "type": "department_entry",
            "id": 1,
            "get": "http:\/\/localhost\/api\/department\/1"
        },
        {
            "type": "department_entry",
            "id": 2,
            "get": "http:\/\/localhost\/api\/department\/2"
        },
        {
            "type": "department_entry",
            "id": 101,
            "get": "http:\/\/localhost\/api\/department\/101"
        },
        {
            "type": "department_entry",
            "id": 102,
            "get": "http:\/\/localhost\/api\/department\/102"
        }
    }
]
```

## get
Get details about a department

### get Request
```GET /department/{identifier}```

### get Parameters
The following get parameters are available:

|Parameter|Meaning|Notes|
|---|---|---|
|identifier|Name or Id of the department||

### get Request Body
Do not supply a request body.

### get Response

An email_entry resource.

```
{
	"email": {string},
	"isAlias": {boolean}
}
```

|Object Property|Value|Description|
|---|---|---|
|email|string|The email address|
|isAlias|boolean|if `true` then an alias|

A department resource.

```
{
    "type": "department",
    "name": {string},
    "division": {string},
    "id": {integer},
    "childCount": {integer},
    "email": [email_entry]
    "fallback": {integer},
    "links": [{HATEOAS links}]
}
```
|Object Property|Value|Description|Includable|
|---|---|---|---|
|type|string|Always "department"|-|
|name|string|Name of the department|-|
|division|string|Name of the division|**yes** `department`|
|id|integer|Id of the department|-|
|childCount|integer|Number of child departments|-|
|email[]|list|List of email_entry resources|-|
|fallback|integer|If set, the `id` of the fallback department. `null` if undefined.|**yes** `department`|
|links[]|list|HATEOAS links|-|

The following HATEOAS methods are available as well:

|HATEOAS Method|Request|Description|
|---|---|---|
|division|GET|Get the department resource for the departments parent division. Only present if the department has a parent.|
|deadlines|GET|Get a list of deadlines for the department.|

### get Code Samples
Request Sample

```
curl -X GET -H 'Authorization: Bearer e0438d90599b1c4762d12fd03db6311c9ca46729' \
   http://localhost:8080/api/department/127?pretty=true
```

Response Sample

```
{
    "name": "IT",
    "division": "Systems",
    "id": 127,
    "childCount": 0,
    "email": [
        {
            "email": "it@convergence-con.org"
            "isAlias": false,
        }
    ],
    "fallback": null,
    "type": "department",
    "links": [
        {
            "method": "self",
            "href": "http:\/\/localhost\/api\/department\/127",
            "request": "GET"
        },
        {
            "method": "division",
            "href": "http:\/\/localhost\/api\/department\/7",
            "request": "GET"
        }
    ]
}
```

## deadlines
Get a list of deadlines for the department.

### deadlines Request

```GET /department/{identifier}/deadlines```

### deadlines Parameters

The following deadlines parameters are available:

|Parameter|Meaning|Notes|
|---|---|---|
|identifier|Name or Id of the department||
|page|Page token for the list.|Defaults to first page.|
|maxResults|Maximum results in the list|Defaults to 100. The token "all" specifies the full remaining list.|

### deadlines Request Body

Do not supply a request body.

### deadlines Response
A [deadline_list](Deadline.md#common_objects) object resource.

### deadlines Code Samples
Request Sample

```
curl -X GET -H 'Authorization: Bearer e0438d90599b1c4762d12fd03db6311c9ca46729' \
    http://localhost/api/department/7/deadlines?pretty=true
```
Response Sample

```
{
    "type": "deadline_list",
    "data": {
        {
            "type": "deadline_entry",
            "id": "5",
            "departmentID": "7",
            "deadline": "2020-11-11",
            "get": "http:\/\/localhost:8080\/api\/deadline\/5"
        },
        {
            "type": "deadline_entry",
            "id": "1",
            "deadline": "2019-12-27",
            "departmentID": "7",
            "get": "http:\/\/localhost:8080\/api\/deadline\/1"
        }
    ]
}
```

## add_deadline
Add a new deadline.

### add_deadline Request

```POST /department/{identifier}/deadline?Deadline={date}&Note={note}```

### add_deadline Parameters
The following parameters are available:

|Parameter|Meaning|Notes|
|---|---|---|
|identifier|Department for which data is being retrieved.|`integer` id or `string` name|
|date|Date of the deadline.|*required*|
|note|Note specifying the deadline.|*required*|

### add_deadline Request Body
Do not supply a request body.

### add_deadline Response

Does not return a response.

### add_deadline Code Samples
Request Sample

```
curl -X POST -H 'Authorization: Bearer e0438d90599b1c4762d12fd03db6311c9ca46729' http://localhost/api/department/Art%20Show/deadline?Deadline=2019-12-27&Note=Testing
```
Response Sample

```
[]
```

## announcements
Get a list of announcements for a department.

### announcements Request

```GET /department/{identifier}/announcements```

### announcements Parameters

The following announcements parameters are available:

|Parameter|Meaning|Notes|
|---|---|---|
|identifier|Name or Id of the member||
|page|Page token for the list.|Defaults to first page.|
|maxResults|Maximum results in the list|Defaults to 100. The token "all" specifies the full remaining list.|

### announcements Request Body

Do not supply a request body.

### announcements Response
A [announcement_list](Announcement.md#common_objects) object resource.

### announcements Code Samples
Request Sample

```
curl -X GET -H 'Authorization: Bearer e0438d90599b1c4762d12fd03db6311c9ca46729' \
    http://localhost/api/department/7/announcements?pretty=true
```
Response Sample

```
{
    "type": "announcement_list",
    "data": {
        {
            "type": "announcement_entry",
            "id": "5",
            "departmentID": "7",
            "postedOn": "2020-11-11",
            "postedBy": 1000,
            "scope": 0,
            "text": "This is an important announcement",
            "get": "http:\/\/localhost:8080\/api\/deadline\/5"
        },
        {
            "type": "deadline_entry",
            "id": "1",
            "departmentID": "7",
            "postedOn": "2020-11-11",
            "postedBy": 1000,
            "scope": 0,
            "text": "This is another very important announcement",
            "get": "http:\/\/localhost:8080\/api\/deadline\/1"
        }
    ]
}
```

## add_announcement
Add a new announcement.

### add_announcement Request

```POST /department/{identifier}/announcement?Scope={integer}&Text={text}[&Email={bool}]```

### add_announcement Parameters
The following parameters are available:

|Parameter|Meaning|Notes|
|---|---|---|
|identifier|Department adding the announcement.|`integer` id or `string` name|
|Scope|Scope of the announcement.|*required*|
|Text|Text of the announcement.|*required*|
|Email|Send announcement via email to all relevant members.|default `true`|

### add_announcement Request Body
Do not supply a request body.

### add_announcement Response

Does not return a response.

### add_announcement Code Samples
Request Sample

```
curl -X POST -H 'Authorization: Bearer e0438d90599b1c4762d12fd03db6311c9ca46729' http://localhost/api/department/Art%20Show/announcement?Scope=0&Text=Testing
```
Response Sample

```
[]
```

---
##### [Return to Top](README.md)           [Return to Resource List](README.md#resources)


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<TITLE>
SequenceChecker (PMD 4.2.5 API)
</TITLE>

<META NAME="date" CONTENT="2009-02-08">

<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">

      Overview
      Package
    Class
      Use
      Tree
      Deprecated
      Index
      Help

 PREV CLASS
 NEXT CLASS

  FRAMES
 NO FRAMES

  All Classes

  SUMMARY: NESTED | FIELD | CONSTR | METHOD

DETAIL: FIELD | CONSTR | METHOD

net.sourceforge.pmd.dfa

Class SequenceChecker

java.lang.Object
  net.sourceforge.pmd.dfa.SequenceChecker

public class SequenceChecker
extends java.lang.Object

Author:

raik

         Computes the first sequence in a list.

         e.g.
         IF_START                       0
         WHILE_EXPR             1
         WHILE_END              2
         IF_END                 3

         The first sequence is WHILE_EXPR und WHILE_END. It returns always the
         first inner nested scope.

Constructor Summary

SequenceChecker(java.util.List bracesList)

Method Summary

 int
getFirstIndex()

 int
getLastIndex()

 boolean
run()

          Finds the first most inner sequence e.g IFStart & IFEnd.

Methods inherited from class java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructor Detail

SequenceChecker

public SequenceChecker(java.util.List bracesList)

Method Detail

run

public boolean run()

Finds the first most inner sequence e.g IFStart & IFEnd. If no sequence
 is found or the list is empty the method returns false.

getFirstIndex

public int getFirstIndex()

getLastIndex

public int getLastIndex()

      Overview
      Package
    Class
      Use
      Tree
      Deprecated
      Index
      Help

 PREV CLASS
 NEXT CLASS

  FRAMES
 NO FRAMES

  All Classes

  SUMMARY: NESTED | FIELD | CONSTR | METHOD

DETAIL: FIELD | CONSTR | METHOD

Copyright © 2002-2009 InfoEther. All Rights Reserved.


text:
<?php include_stylesheets()?>

        <?php if($sf_user->getFlash('message')){?>
              <?php echo $sf_user->getFlash('message')?>
        <?php }else{?>
        <form name="form_sharebyMail"  id="form_sharebyMail" class="form_sharebyMail" action="<?php echo url_for('pubs/sendShare') ?>" method="post" enctype="multipart/form-data">

                         <tr <?php if ($form['sender']->renderError()) echo 'class="error"' ?>>

                                <span class="label <?php if ($form['sender']->renderError()) echo "error" ?>">
                                    From

                                <?php echo $form['sender']->render(array("size" => "40", "id" => "input")) ?>

                        <tr <?php if ($form['dest']->renderError()) echo 'class="error"' ?>>

                                <span class="label <?php if ($form['dest']->renderError()) echo "error" ?>">
                                    To

                              <?php echo $form['dest']->render(array("size" => "40", "id" => "input")) ?>

                        <tr <?php if ($form['description']->renderError()) echo 'class="error"' ?>>

                                 Message

                                <?php echo $form['description']->render(array("id" => "input_description")) ?>

                                <?php echo image_tag('/PubsPlugin/images/loading.gif') ?>  <input class="button"  type="submit" value="Enviar" />

            <?php echo $form->renderHiddenFields(); ?>
        </form>
        <?php }?>


text:
		<rest-ful
			data-rest-class="pull"
			data-rest-url="http://api.geonames.org/postalCodeLookupJSON"
			data-rest-cross-domain="true"
			data-rest-handlebars-template="rest-template"
			data-rest-handlebars-content="handlebars-data-holder">
			{
				postalcode: 6600,
				username: "<your-username-here>"
			}
		</rest-ful>


text:
#ifndef _EASY_GETTEXT_DEFINES_
#define _EASY_GETTEXT_DEFINES_ 1

#ifndef _EASY_GETTEXT_COMPILE_TIME_
typedef void* EasyGettext;
#endif

#ifdef EASY_GETTEXT_STATIC
  #define _EAG_LOC_
  #define _EAG_PUB_
#elif defined _WIN32 || defined __CYGWIN__ || defined _WIN64
  #define _EAG_LOC_
  #ifdef _EASY_GETTEXT_COMPILE_TIME_
    #define _EAG_PUB_ __declspec(dllexport)
  #else
    #define _EAG_PUB_ __declspec(dllimport)
  #endif
#else
  #if __GNUC__ >= 4
    #define _EAG_PUB_ __attribute__ ((visibility ("default")))
    #define _EAG_LOC_  __attribute__ ((visibility ("hidden")))
  #else
    #define _EAG_PUB_
    #define _EAG_LOC_
  #endif
#endif

#ifndef EASY_GETTEXT_NO_REPLACE
  #ifdef _
    #undef _
  #endif
  #define _(A) EasyGettext_gettext(&EasyGettext_default,A)

  #ifdef gettext
    #undef gettext
  #endif
  #define gettext(A) EasyGettext_gettext(&EasyGettext_default,A)

  #ifdef ngettext
    #undef ngettext
  #endif
  #define ngettext(A,B,C) EasyGettext_ngettext(&EasyGettext_default,A,B,C)
#endif

#ifndef EASY_GETTEXT_NO_REDUCTION
  #define EG_(A) EasyGettext_gettext(&EasyGettext_default,A)
  #define EG_N(A,B,C) EasyGettext_ngettext(&EasyGettext_default,A,B,C)
  #define EG_init(A,B) EasyGettext_init(&EasyGettext_default,A,B)
  #define EG_clean() EasyGettext_clean(&EasyGettext_default)
#endif

#endif


text:
package com.xmgps.yfzx.hwb.vertx;

import com.xmgps.yfzx.hwb.vertx.util.Runner;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetClient;
import io.vertx.core.net.NetSocket;

import java.util.concurrent.*;

/**
 * Created by gps_hwb on 2015/9/8.
 */
public class MyClient extends AbstractVerticle {

    public NetSocket socket = null;

    public static void main(String[] args) {
        Runner.runExample(MyClient.class);
    }

    public boolean connect(String ip,int port){
        NetClient connect = vertx.createNetClient().connect(port, ip, handler -> {
            if (handler.succeeded()) {
                NetSocket socket = handler.result();
                this.socket = socket;

                socket.handler(buffer -> {
                    System.out.println("Net client receiving: " + buffer.toString("UTF-8"));
                });
                socket.exceptionHandler(throwable -> {
                    System.out.println("Net client Exception: " + throwable.getMessage());
                });
                //socket.drainHandler( drain -> System.out.println("Net client drain! "));
                socket.closeHandler(close -> System.out.println("Net client close! " + socket.localAddress().toString()));
                socket.endHandler(end -> {
                    System.out.println("Net client end! " + socket.localAddress().toString());
                    connect(ip, port);
                });
            } else {
                System.out.println("Failed to connect " + handler.cause());
                connect(ip, port);
            }

        });

        return true;
    }

    public boolean sendMessage(Buffer buffer){
        if(socket!=null)
            socket.write(buffer).endHandler(end -> System.out.println("Net client send end!"));
        else
            return false;
        //TODO
        return true;
    }

    public boolean keeplive(){
        ScheduledExecutorService service = Executors
                .newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                sendMessage(Buffer.buffer("keeplive"));
            }
        }, 10, 1, TimeUnit.SECONDS);
        return true;
    }

    @Override
    public void start() throws Exception {
        this.connect("127.0.0.1", 1234);
        this.sendMessage(Buffer.buffer("test123"));
        this.sendMessage(Buffer.buffer("test123"));
        this.sendMessage(Buffer.buffer("test123"));
        this.sendMessage(Buffer.buffer("test123"));
        this.keeplive();
    }
}


text:
"""django_rv_apps URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url, include
from django.contrib import admin
from rest_framework_swagger.views import get_swagger_view

schema_view = get_swagger_view(title='Pastebin API')

import debug_toolbar

urlpatterns = [
    url(r'^jet/', include('jet.urls', 'jet')),  # Django JET URLS
    url(r'^admin/', admin.site.urls),
    url(r'^api-auth/', include('rest_framework.urls')),

    url(r'^schema/', schema_view),
    url(r'^api/believe/', include('django_rv_apps.apps.believe_his_prophets_api.urls')),
    url(r'^__debug__/', include(debug_toolbar.urls)),

]


text:
namespace Auth0.ClaimsProvider.Configuration
{
    using System;
    using System.Collections.Generic;
    using Microsoft.SharePoint.Administration;
    using Microsoft.SharePoint.Administration.Claims;
    using Microsoft.SharePoint.WebControls;

    public class ConfigurationRepository : IConfigurationRepository
    {
        public const string Auth0PersistedObjectName = "Auth0ClaimsProviderConfig";

        public Auth0Config GetConfiguration()
        {
            var configuration = SPFarm.Local.GetChild<Auth0Config>(Auth0PersistedObjectName) ??
                                CreatePersistedObject();

            if (string.IsNullOrEmpty(configuration.PickerEntityGroupName))
            {
                configuration.PickerEntityGroupName = "Results";
            }

            if (string.IsNullOrEmpty(configuration.IdentifierUserField))
            {
                configuration.IdentifierUserField = "Email";
            }

            return configuration;
        }

        public void SaveConfiguration(Auth0Config auth0Config)
        {
            if (auth0Config != null)
            {
                auth0Config.Update();
            }
        }

        private static Auth0Config CreatePersistedObject()
        {
            var persistedObject = new Auth0Config(Auth0PersistedObjectName, SPFarm.Local);
            persistedObject.Update();

            return persistedObject;
        }
    }
}


text:
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>

#include <media/videobuf2-core.h>
#include <media/videobuf2-memops.h>
#include <media/videobuf2-dma-sg.h>

static int debug;
module_param(debug, int, 0644);

#define dprintk(level, fmt, arg...)					\
	do {								\
		if (debug >= level)					\
			printk(KERN_DEBUG "vb2-dma-sg: " fmt, ## arg);	\
	} while (0)

struct vb2_dma_sg_conf {
	struct device		*dev;
};

struct vb2_dma_sg_buf {
	struct device			*dev;
	void				*vaddr;
	struct page			**pages;
	struct frame_vector		*vec;
	int				offset;
	enum dma_data_direction		dma_dir;
	struct sg_table			sg_table;
	/*
	 * This will point to sg_table when used with the MMAP or USERPTR
	 * memory model, and to the dma_buf sglist when used with the
	 * DMABUF memory model.
	 */
	struct sg_table			*dma_sgt;
	size_t				size;
	unsigned int			num_pages;
	atomic_t			refcount;
	struct vb2_vmarea_handler	handler;

	struct dma_buf_attachment	*db_attach;
};

static void vb2_dma_sg_put(void *buf_priv);

static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf,
		gfp_t gfp_flags)
{
	unsigned int last_page = 0;
	int size = buf->size;

	while (size > 0) {
		struct page *pages;
		int order;
		int i;

		order = get_order(size);
		/* Dont over allocate*/
		if ((PAGE_SIZE << order) > size)
			order--;

		pages = NULL;
		while (!pages) {
			pages = alloc_pages(GFP_KERNEL | __GFP_ZERO |
					__GFP_NOWARN | gfp_flags, order);
			if (pages)
				break;

			if (order == 0) {
				while (last_page--)
					__free_page(buf->pages[last_page]);
				return -ENOMEM;
			}
			order--;
		}

		split_page(pages, order);
		for (i = 0; i < (1 << order); i++)
			buf->pages[last_page++] = &pages[i];

		size -= PAGE_SIZE << order;
	}

	return 0;
}

static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size,
			      enum dma_data_direction dma_dir, gfp_t gfp_flags)
{
	struct vb2_dma_sg_conf *conf = alloc_ctx;
	struct vb2_dma_sg_buf *buf;
	struct sg_table *sgt;
	int ret;
	int num_pages;
	DEFINE_DMA_ATTRS(attrs);

	dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);

	if (WARN_ON(alloc_ctx == NULL))
		return NULL;
	buf = kzalloc(sizeof *buf, GFP_KERNEL);
	if (!buf)
		return NULL;

	buf->vaddr = NULL;
	buf->dma_dir = dma_dir;
	buf->offset = 0;
	buf->size = size;
	/* size is already page aligned */
	buf->num_pages = size >> PAGE_SHIFT;
	buf->dma_sgt = &buf->sg_table;

	buf->pages = kzalloc(buf->num_pages * sizeof(struct page *),
			     GFP_KERNEL);
	if (!buf->pages)
		goto fail_pages_array_alloc;

	ret = vb2_dma_sg_alloc_compacted(buf, gfp_flags);
	if (ret)
		goto fail_pages_alloc;

	ret = sg_alloc_table_from_pages(buf->dma_sgt, buf->pages,
			buf->num_pages, 0, size, GFP_KERNEL);
	if (ret)
		goto fail_table_alloc;

	/* Prevent the device from being released while the buffer is used */
	buf->dev = get_device(conf->dev);

	sgt = &buf->sg_table;
	/*
	 * No need to sync to the device, this will happen later when the
	 * prepare() memop is called.
	 */
	sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
				      buf->dma_dir, &attrs);
	if (!sgt->nents)
		goto fail_map;

	buf->handler.refcount = &buf->refcount;
	buf->handler.put = vb2_dma_sg_put;
	buf->handler.arg = buf;

	atomic_inc(&buf->refcount);

	dprintk(1, "%s: Allocated buffer of %d pages\n",
		__func__, buf->num_pages);
	return buf;

fail_map:
	put_device(buf->dev);
	sg_free_table(buf->dma_sgt);
fail_table_alloc:
	num_pages = buf->num_pages;
	while (num_pages--)
		__free_page(buf->pages[num_pages]);
fail_pages_alloc:
	kfree(buf->pages);
fail_pages_array_alloc:
	kfree(buf);
	return NULL;
}

static void vb2_dma_sg_put(void *buf_priv)
{
	struct vb2_dma_sg_buf *buf = buf_priv;
	struct sg_table *sgt = &buf->sg_table;
	int i = buf->num_pages;

	if (atomic_dec_and_test(&buf->refcount)) {
		DEFINE_DMA_ATTRS(attrs);

		dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
		dprintk(1, "%s: Freeing buffer of %d pages\n", __func__,
			buf->num_pages);
		dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
				   buf->dma_dir, &attrs);
		if (buf->vaddr)
			vm_unmap_ram(buf->vaddr, buf->num_pages);
		sg_free_table(buf->dma_sgt);
		while (--i >= 0)
			__free_page(buf->pages[i]);
		kfree(buf->pages);
		put_device(buf->dev);
		kfree(buf);
	}
}

static void vb2_dma_sg_prepare(void *buf_priv)
{
	struct vb2_dma_sg_buf *buf = buf_priv;
	struct sg_table *sgt = buf->dma_sgt;

	/* DMABUF exporter will flush the cache for us */
	if (buf->db_attach)
		return;

	dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
}

static void vb2_dma_sg_finish(void *buf_priv)
{
	struct vb2_dma_sg_buf *buf = buf_priv;
	struct sg_table *sgt = buf->dma_sgt;

	/* DMABUF exporter will flush the cache for us */
	if (buf->db_attach)
		return;

	dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
}

static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
				    unsigned long size,
				    enum dma_data_direction dma_dir)
{
	struct vb2_dma_sg_conf *conf = alloc_ctx;
	struct vb2_dma_sg_buf *buf;
	struct sg_table *sgt;
	DEFINE_DMA_ATTRS(attrs);
	struct frame_vector *vec;

	dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
	buf = kzalloc(sizeof *buf, GFP_KERNEL);
	if (!buf)
		return NULL;

	buf->vaddr = NULL;
	buf->dev = conf->dev;
	buf->dma_dir = dma_dir;
	buf->offset = vaddr & ~PAGE_MASK;
	buf->size = size;
	buf->dma_sgt = &buf->sg_table;
	vec = vb2_create_framevec(vaddr, size, buf->dma_dir == DMA_FROM_DEVICE);
	if (IS_ERR(vec))
		goto userptr_fail_pfnvec;
	buf->vec = vec;

	buf->pages = frame_vector_pages(vec);
	if (IS_ERR(buf->pages))
		goto userptr_fail_sgtable;
	buf->num_pages = frame_vector_count(vec);

	if (sg_alloc_table_from_pages(buf->dma_sgt, buf->pages,
			buf->num_pages, buf->offset, size, 0))
		goto userptr_fail_sgtable;

	sgt = &buf->sg_table;
	/*
	 * No need to sync to the device, this will happen later when the
	 * prepare() memop is called.
	 */
	sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
				      buf->dma_dir, &attrs);
	if (!sgt->nents)
		goto userptr_fail_map;

	return buf;

userptr_fail_map:
	sg_free_table(&buf->sg_table);
userptr_fail_sgtable:
	vb2_destroy_framevec(vec);
userptr_fail_pfnvec:
	kfree(buf);
	return NULL;
}

/*
 * @put_userptr: inform the allocator that a USERPTR buffer will no longer
 *		 be used
 */
static void vb2_dma_sg_put_userptr(void *buf_priv)
{
	struct vb2_dma_sg_buf *buf = buf_priv;
	struct sg_table *sgt = &buf->sg_table;
	int i = buf->num_pages;
	DEFINE_DMA_ATTRS(attrs);

	dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);

	dprintk(1, "%s: Releasing userspace buffer of %d pages\n",
	       __func__, buf->num_pages);
	dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir,
			   &attrs);
	if (buf->vaddr)
		vm_unmap_ram(buf->vaddr, buf->num_pages);
	sg_free_table(buf->dma_sgt);
	while (--i >= 0) {
		if (buf->dma_dir == DMA_FROM_DEVICE)
			set_page_dirty_lock(buf->pages[i]);
	}
	vb2_destroy_framevec(buf->vec);
	kfree(buf);
}

static void *vb2_dma_sg_vaddr(void *buf_priv)
{
	struct vb2_dma_sg_buf *buf = buf_priv;

	BUG_ON(!buf);

	if (!buf->vaddr) {
		if (buf->db_attach)
			buf->vaddr = dma_buf_vmap(buf->db_attach->dmabuf);
		else
			buf->vaddr = vm_map_ram(buf->pages,
					buf->num_pages, -1, PAGE_KERNEL);
	}

	/* add offset in case userptr is not page-aligned */
	return buf->vaddr ? buf->vaddr + buf->offset : NULL;
}

static unsigned int vb2_dma_sg_num_users(void *buf_priv)
{
	struct vb2_dma_sg_buf *buf = buf_priv;

	return atomic_read(&buf->refcount);
}

static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma)
{
	struct vb2_dma_sg_buf *buf = buf_priv;
	unsigned long uaddr = vma->vm_start;
	unsigned long usize = vma->vm_end - vma->vm_start;
	int i = 0;

	if (!buf) {
		printk(KERN_ERR "No memory to map\n");
		return -EINVAL;
	}

	do {
		int ret;

		ret = vm_insert_page(vma, uaddr, buf->pages[i++]);
		if (ret) {
			printk(KERN_ERR "Remapping memory, error: %d\n", ret);
			return ret;
		}

		uaddr += PAGE_SIZE;
		usize -= PAGE_SIZE;
	} while (usize > 0);

	/*
	 * Use common vm_area operations to track buffer refcount.
	 */
	vma->vm_private_data	= &buf->handler;
	vma->vm_ops		= &vb2_common_vm_ops;

	vma->vm_ops->open(vma);

	return 0;
}

/*********************************************/
/*         DMABUF ops for exporters          */
/*********************************************/

struct vb2_dma_sg_attachment {
	struct sg_table sgt;
	enum dma_data_direction dma_dir;
};

static int vb2_dma_sg_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev,
	struct dma_buf_attachment *dbuf_attach)
{
	struct vb2_dma_sg_attachment *attach;
	unsigned int i;
	struct scatterlist *rd, *wr;
	struct sg_table *sgt;
	struct vb2_dma_sg_buf *buf = dbuf->priv;
	int ret;

	attach = kzalloc(sizeof(*attach), GFP_KERNEL);
	if (!attach)
		return -ENOMEM;

	sgt = &attach->sgt;
	/* Copy the buf->base_sgt scatter list to the attachment, as we can't
	 * map the same scatter list to multiple attachments at the same time.
	 */
	ret = sg_alloc_table(sgt, buf->dma_sgt->orig_nents, GFP_KERNEL);
	if (ret) {
		kfree(attach);
		return -ENOMEM;
	}

	rd = buf->dma_sgt->sgl;
	wr = sgt->sgl;
	for (i = 0; i < sgt->orig_nents; ++i) {
		sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
		rd = sg_next(rd);
		wr = sg_next(wr);
	}

	attach->dma_dir = DMA_NONE;
	dbuf_attach->priv = attach;

	return 0;
}

static void vb2_dma_sg_dmabuf_ops_detach(struct dma_buf *dbuf,
	struct dma_buf_attachment *db_attach)
{
	struct vb2_dma_sg_attachment *attach = db_attach->priv;
	struct sg_table *sgt;

	if (!attach)
		return;

	sgt = &attach->sgt;

	/* release the scatterlist cache */
	if (attach->dma_dir != DMA_NONE)
		dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
			attach->dma_dir);
	sg_free_table(sgt);
	kfree(attach);
	db_attach->priv = NULL;
}

static struct sg_table *vb2_dma_sg_dmabuf_ops_map(
	struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir)
{
	struct vb2_dma_sg_attachment *attach = db_attach->priv;
	/* stealing dmabuf mutex to serialize map/unmap operations */
	struct mutex *lock = &db_attach->dmabuf->lock;
	struct sg_table *sgt;

	mutex_lock(lock);

	sgt = &attach->sgt;
	/* return previously mapped sg table */
	if (attach->dma_dir == dma_dir) {
		mutex_unlock(lock);
		return sgt;
	}

	/* release any previous cache */
	if (attach->dma_dir != DMA_NONE) {
		dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
			attach->dma_dir);
		attach->dma_dir = DMA_NONE;
	}

	/* mapping to the client with new direction */
	sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
				dma_dir);
	if (!sgt->nents) {
		pr_err("failed to map scatterlist\n");
		mutex_unlock(lock);
		return ERR_PTR(-EIO);
	}

	attach->dma_dir = dma_dir;

	mutex_unlock(lock);

	return sgt;
}

static void vb2_dma_sg_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach,
	struct sg_table *sgt, enum dma_data_direction dma_dir)
{
	/* nothing to be done here */
}

static void vb2_dma_sg_dmabuf_ops_release(struct dma_buf *dbuf)
{
	/* drop reference obtained in vb2_dma_sg_get_dmabuf */
	vb2_dma_sg_put(dbuf->priv);
}

static void *vb2_dma_sg_dmabuf_ops_kmap(struct dma_buf *dbuf, unsigned long pgnum)
{
	struct vb2_dma_sg_buf *buf = dbuf->priv;

	return buf->vaddr ? buf->vaddr + pgnum * PAGE_SIZE : NULL;
}

static void *vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf)
{
	struct vb2_dma_sg_buf *buf = dbuf->priv;

	return vb2_dma_sg_vaddr(buf);
}

static int vb2_dma_sg_dmabuf_ops_mmap(struct dma_buf *dbuf,
	struct vm_area_struct *vma)
{
	return vb2_dma_sg_mmap(dbuf->priv, vma);
}

static struct dma_buf_ops vb2_dma_sg_dmabuf_ops = {
	.attach = vb2_dma_sg_dmabuf_ops_attach,
	.detach = vb2_dma_sg_dmabuf_ops_detach,
	.map_dma_buf = vb2_dma_sg_dmabuf_ops_map,
	.unmap_dma_buf = vb2_dma_sg_dmabuf_ops_unmap,
	.kmap = vb2_dma_sg_dmabuf_ops_kmap,
	.kmap_atomic = vb2_dma_sg_dmabuf_ops_kmap,
	.vmap = vb2_dma_sg_dmabuf_ops_vmap,
	.mmap = vb2_dma_sg_dmabuf_ops_mmap,
	.release = vb2_dma_sg_dmabuf_ops_release,
};

static struct dma_buf *vb2_dma_sg_get_dmabuf(void *buf_priv, unsigned long flags)
{
	struct vb2_dma_sg_buf *buf = buf_priv;
	struct dma_buf *dbuf;
	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);

	exp_info.ops = &vb2_dma_sg_dmabuf_ops;
	exp_info.size = buf->size;
	exp_info.flags = flags;
	exp_info.priv = buf;

	if (WARN_ON(!buf->dma_sgt))
		return NULL;

	dbuf = dma_buf_export(&exp_info);
	if (IS_ERR(dbuf))
		return NULL;

	/* dmabuf keeps reference to vb2 buffer */
	atomic_inc(&buf->refcount);

	return dbuf;
}

/*********************************************/
/*       callbacks for DMABUF buffers        */
/*********************************************/

static int vb2_dma_sg_map_dmabuf(void *mem_priv)
{
	struct vb2_dma_sg_buf *buf = mem_priv;
	struct sg_table *sgt;

	if (WARN_ON(!buf->db_attach)) {
		pr_err("trying to pin a non attached buffer\n");
		return -EINVAL;
	}

	if (WARN_ON(buf->dma_sgt)) {
		pr_err("dmabuf buffer is already pinned\n");
		return 0;
	}

	/* get the associated scatterlist for this buffer */
	sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir);
	if (IS_ERR(sgt)) {
		pr_err("Error getting dmabuf scatterlist\n");
		return -EINVAL;
	}

	buf->dma_sgt = sgt;
	buf->vaddr = NULL;

	return 0;
}

static void vb2_dma_sg_unmap_dmabuf(void *mem_priv)
{
	struct vb2_dma_sg_buf *buf = mem_priv;
	struct sg_table *sgt = buf->dma_sgt;

	if (WARN_ON(!buf->db_attach)) {
		pr_err("trying to unpin a not attached buffer\n");
		return;
	}

	if (WARN_ON(!sgt)) {
		pr_err("dmabuf buffer is already unpinned\n");
		return;
	}

	if (buf->vaddr) {
		dma_buf_vunmap(buf->db_attach->dmabuf, buf->vaddr);
		buf->vaddr = NULL;
	}
	dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir);

	buf->dma_sgt = NULL;
}

static void vb2_dma_sg_detach_dmabuf(void *mem_priv)
{
	struct vb2_dma_sg_buf *buf = mem_priv;

	/* if vb2 works correctly you should never detach mapped buffer */
	if (WARN_ON(buf->dma_sgt))
		vb2_dma_sg_unmap_dmabuf(buf);

	/* detach this attachment */
	dma_buf_detach(buf->db_attach->dmabuf, buf->db_attach);
	kfree(buf);
}

static void *vb2_dma_sg_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf,
	unsigned long size, enum dma_data_direction dma_dir)
{
	struct vb2_dma_sg_conf *conf = alloc_ctx;
	struct vb2_dma_sg_buf *buf;
	struct dma_buf_attachment *dba;

	if (dbuf->size < size)
		return ERR_PTR(-EFAULT);

	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
	if (!buf)
		return ERR_PTR(-ENOMEM);

	buf->dev = conf->dev;
	/* create attachment for the dmabuf with the user device */
	dba = dma_buf_attach(dbuf, buf->dev);
	if (IS_ERR(dba)) {
		pr_err("failed to attach dmabuf\n");
		kfree(buf);
		return dba;
	}

	buf->dma_dir = dma_dir;
	buf->size = size;
	buf->db_attach = dba;

	return buf;
}

static void *vb2_dma_sg_cookie(void *buf_priv)
{
	struct vb2_dma_sg_buf *buf = buf_priv;

	return buf->dma_sgt;
}

const struct vb2_mem_ops vb2_dma_sg_memops = {
	.alloc		= vb2_dma_sg_alloc,
	.put		= vb2_dma_sg_put,
	.get_userptr	= vb2_dma_sg_get_userptr,
	.put_userptr	= vb2_dma_sg_put_userptr,
	.prepare	= vb2_dma_sg_prepare,
	.finish		= vb2_dma_sg_finish,
	.vaddr		= vb2_dma_sg_vaddr,
	.mmap		= vb2_dma_sg_mmap,
	.num_users	= vb2_dma_sg_num_users,
	.get_dmabuf	= vb2_dma_sg_get_dmabuf,
	.map_dmabuf	= vb2_dma_sg_map_dmabuf,
	.unmap_dmabuf	= vb2_dma_sg_unmap_dmabuf,
	.attach_dmabuf	= vb2_dma_sg_attach_dmabuf,
	.detach_dmabuf	= vb2_dma_sg_detach_dmabuf,
	.cookie		= vb2_dma_sg_cookie,
};
EXPORT_SYMBOL_GPL(vb2_dma_sg_memops);

void *vb2_dma_sg_init_ctx(struct device *dev)
{
	struct vb2_dma_sg_conf *conf;

	conf = kzalloc(sizeof(*conf), GFP_KERNEL);
	if (!conf)
		return ERR_PTR(-ENOMEM);

	conf->dev = dev;

	return conf;
}
EXPORT_SYMBOL_GPL(vb2_dma_sg_init_ctx);

void vb2_dma_sg_cleanup_ctx(void *alloc_ctx)
{
	if (!IS_ERR_OR_NULL(alloc_ctx))
		kfree(alloc_ctx);
}
EXPORT_SYMBOL_GPL(vb2_dma_sg_cleanup_ctx);

MODULE_DESCRIPTION("dma scatter/gather memory handling routines for videobuf2");
MODULE_AUTHOR("Andrzej Pietrasiewicz");
MODULE_LICENSE("GPL");