text:
package com.facebook.buck.test.selectors;

import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**
 * A {@link TestDescription} will match if this selector's class-part is a substring of the {@link
 * TestDescription}'s full class-name, or if this selector's class-name, when interpreted as a
 * java.util.regex regular-expression, matches the {@link TestDescription}'s full class-name.
 *
 *
(The same rules apply for the method-name as well. If this selector's class-part or
 * method-part are null, all class-names or method-names will match.)
 */
public class PatternTestSelector implements TestSelector {

  static final PatternTestSelector INCLUDE_EVERYTHING = new PatternTestSelector(true, null, null);
  static final PatternTestSelector EXCLUDE_EVERYTHING = new PatternTestSelector(false, null, null);

  private final boolean inclusive;
  @Nullable private final Pattern classPattern;
  @Nullable private final Pattern methodPattern;

  private PatternTestSelector(
      boolean inclusive, @Nullable Pattern classPattern, @Nullable Pattern methodPattern) {
    this.inclusive = inclusive;
    this.classPattern = classPattern;
    this.methodPattern = methodPattern;
  }

  /**
   * Build a {@link PatternTestSelector} from the given String. Selector strings should be of the
   * form "[is-exclusive][class-part]#[method-part]". If "[is-exclusive]" is a "!" then this
   * selector will exclude tests, otherwise it will include tests.
   *
   *
If the class-part (or method-part) are omitted, then all classes or methods will match.
   * Consequently "#" means "include everything" and "!#" means "exclude everything".
   *
   *
If the selector string doesn't contain a "#" at all, it is interpreted as a class-part.
   *
   * @param rawSelectorString An unparsed selector string.
   */
  public static TestSelector buildFromSelectorString(String rawSelectorString) {
    if (rawSelectorString == null || rawSelectorString.isEmpty()) {
      throw new RuntimeException("Cannot build from a null or empty string!");
    }

    boolean isInclusive = true;
    String remainder;
    if (rawSelectorString.charAt(0) == '!') {
      isInclusive = false;
      remainder = rawSelectorString.substring(1);
    } else {
      remainder = rawSelectorString;
    }
    // Reuse universal inclusion
    if (remainder.equals("#")) {
      return isInclusive ? INCLUDE_EVERYTHING : EXCLUDE_EVERYTHING;
    }

    Pattern classPattern;
    Pattern methodPattern = null;
    // we only apply splitting once. parameterized tests can have parameterization names that
    // contains the symbol "#" in its method. e.g ClassTest#methodTest[Param#name]. So we should
    // only split on the first "#" as class names cannot contain that symbol.
    String[] parts = remainder.split("#", 2);

    try {
      if (parts.length == 1) {
        // "com.example.Test", "com.example.Test#"
        classPattern = getPatternOrNull(parts[0]);
      } else {
        if (parts[1].startsWith("#")) {
          throw new TestSelectorParseException(
              String.format("Invalid method pattern ## in %s", rawSelectorString));
        }
        // "com.example.Test#testX", "#testX", "#"
        classPattern = getPatternOrNull(parts[0]);
        methodPattern = getPatternOrNull(parts[1]);
      }
    } catch (PatternSyntaxException e) {
      throw new TestSelectorParseException(
          String.format("Regular expression error in '%s': %s", rawSelectorString, e.getMessage()));
    }

    return new PatternTestSelector(isInclusive, classPattern, methodPattern);
  }

  @Override
  public String getRawSelector() {
    StringBuilder builder = new StringBuilder();
    if (!inclusive) {
      builder.append('!');
    }
    if (classPattern != null) {
      builder.append(classPattern);
    }
    builder.append('#');
    if (methodPattern != null) {
      builder.append(methodPattern);
    }
    return builder.toString();
  }

  @Nullable
  private static Pattern getPatternOrNull(String string) {
    if (string.isEmpty()) {
      return null;
    } else {
      if (!string.endsWith("$")) {
        string = string + "$";
      }
      return Pattern.compile(string);
    }
  }

  @Override
  public String getExplanation() {
    if (isMatchAnyClass() && isMatchAnyMethod()) {
      return isInclusive() ? "include everything else" : "exclude everything else";
    }
    return String.format(
        "%s class:%s method:%s",
        isInclusive() ? "include" : "exclude",
        isMatchAnyClass() ? "<any>" : classPattern,
        isMatchAnyMethod() ? "<any>" : methodPattern);
  }

  @Override
  public boolean isInclusive() {
    return inclusive;
  }

  @Override
  public boolean isMatchAnyClass() {
    return classPattern == null;
  }

  @Override
  public boolean isMatchAnyMethod() {
    return methodPattern == null;
  }

  @Override
  public boolean matches(TestDescription description) {
    return matchesClassName(description.getClassName())
        && matchesMethodName(description.getMethodName());
  }

  @Override
  public boolean matchesClassName(String className) {
    if (classPattern == null || className == null) {
      return true;
    }
    return classPattern.matcher(className).find();
  }

  @Override
  public boolean containsClassPath(String classPath) {
    if (classPattern == null) {
      return true;
    }
    // Find occurrence of "\$" in the pattern, which indicates a nested class
    String[] outerInnerPatterns = classPattern.toString().split("\\\\\\$");
    if (outerInnerPatterns.length == 2) {
      // If we have an outer class, we should ensure that we are treating the outer class pattern as
      // matching the end of the classpath, so add a "$"
      // e.g: pattern of "Foo\$Bar" means it should only match outer classpaths of "Foo", not "FooF"
      outerInnerPatterns[0] += "$";
    }
    return Pattern.compile(outerInnerPatterns[0]).matcher(classPath).find();
  }

  private boolean matchesMethodName(String methodName) {
    if (methodPattern == null || methodName == null) {
      return true;
    }
    return methodPattern.matcher(methodName).find();
  }
}


text:
package com.amazonaws.services.translate.model;

import java.io.Serializable;
import javax.annotation.Generated;
import com.amazonaws.protocol.StructuredPojo;
import com.amazonaws.protocol.ProtocolMarshaller;

/**
 *

 * Specifies the format and S3 location of the parallel data input file.
 *

 *
 * @see AWS API
 *      Documentation
 */
@Generated("com.amazonaws:aws-java-sdk-code-generator")
public class ParallelDataConfig implements Serializable, Cloneable, StructuredPojo {

    /**
     *

     * The URI of the Amazon S3 folder that contains the parallel data input file. The folder must be in the same Region
     * as the API endpoint you are calling.
     *

     */
    private String s3Uri;
    /**
     *

     * The format of the parallel data input file.
     *

     */
    private String format;

    /**
     *

     * The URI of the Amazon S3 folder that contains the parallel data input file. The folder must be in the same Region
     * as the API endpoint you are calling.
     *

     *
     * @param s3Uri
     *        The URI of the Amazon S3 folder that contains the parallel data input file. The folder must be in the same
     *        Region as the API endpoint you are calling.
     */

    public void setS3Uri(String s3Uri) {
        this.s3Uri = s3Uri;
    }

    /**
     *

     * The URI of the Amazon S3 folder that contains the parallel data input file. The folder must be in the same Region
     * as the API endpoint you are calling.
     *

     *
     * @return The URI of the Amazon S3 folder that contains the parallel data input file. The folder must be in the
     *         same Region as the API endpoint you are calling.
     */

    public String getS3Uri() {
        return this.s3Uri;
    }

    /**
     *

     * The URI of the Amazon S3 folder that contains the parallel data input file. The folder must be in the same Region
     * as the API endpoint you are calling.
     *

     *
     * @param s3Uri
     *        The URI of the Amazon S3 folder that contains the parallel data input file. The folder must be in the same
     *        Region as the API endpoint you are calling.
     * @return Returns a reference to this object so that method calls can be chained together.
     */

    public ParallelDataConfig withS3Uri(String s3Uri) {
        setS3Uri(s3Uri);
        return this;
    }

    /**
     *

     * The format of the parallel data input file.
     *

     *
     * @param format
     *        The format of the parallel data input file.
     * @see ParallelDataFormat
     */

    public void setFormat(String format) {
        this.format = format;
    }

    /**
     *

     * The format of the parallel data input file.
     *

     *
     * @return The format of the parallel data input file.
     * @see ParallelDataFormat
     */

    public String getFormat() {
        return this.format;
    }

    /**
     *

     * The format of the parallel data input file.
     *

     *
     * @param format
     *        The format of the parallel data input file.
     * @return Returns a reference to this object so that method calls can be chained together.
     * @see ParallelDataFormat
     */

    public ParallelDataConfig withFormat(String format) {
        setFormat(format);
        return this;
    }

    /**
     *

     * The format of the parallel data input file.
     *

     *
     * @param format
     *        The format of the parallel data input file.
     * @return Returns a reference to this object so that method calls can be chained together.
     * @see ParallelDataFormat
     */

    public ParallelDataConfig withFormat(ParallelDataFormat format) {
        this.format = format.toString();
        return this;
    }

    /**
     * Returns a string representation of this object. This is useful for testing and debugging. Sensitive data will be
     * redacted from this string using a placeholder value.
     *
     * @return A string representation of this object.
     *
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("{");
        if (getS3Uri() != null)
            sb.append("S3Uri: ").append(getS3Uri()).append(",");
        if (getFormat() != null)
            sb.append("Format: ").append(getFormat());
        sb.append("}");
        return sb.toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;

        if (obj instanceof ParallelDataConfig == false)
            return false;
        ParallelDataConfig other = (ParallelDataConfig) obj;
        if (other.getS3Uri() == null ^ this.getS3Uri() == null)
            return false;
        if (other.getS3Uri() != null && other.getS3Uri().equals(this.getS3Uri()) == false)
            return false;
        if (other.getFormat() == null ^ this.getFormat() == null)
            return false;
        if (other.getFormat() != null && other.getFormat().equals(this.getFormat()) == false)
            return false;
        return true;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int hashCode = 1;

        hashCode = prime * hashCode + ((getS3Uri() == null) ? 0 : getS3Uri().hashCode());
        hashCode = prime * hashCode + ((getFormat() == null) ? 0 : getFormat().hashCode());
        return hashCode;
    }

    @Override
    public ParallelDataConfig clone() {
        try {
            return (ParallelDataConfig) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new IllegalStateException("Got a CloneNotSupportedException from Object.clone() " + "even though we're Cloneable!", e);
        }
    }

    @com.amazonaws.annotation.SdkInternalApi
    @Override
    public void marshall(ProtocolMarshaller protocolMarshaller) {
        com.amazonaws.services.translate.model.transform.ParallelDataConfigMarshaller.getInstance().marshall(this, protocolMarshaller);
    }
}

redpajama_set_name: RedPajamaGithub


text:
'use strict';

module.exports = require('./is-implemented')() ? Math.fround : require('./shim');

//# sourceMappingURL=index-compiled.js.map


text:
package bs.util.tool.commongui.plugins;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFormattedTextField;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import bs.util.io.PropertiesUtils;
import bs.util.tool.commongui.GuiJPanel;
import bs.util.tool.commongui.GuiUtils;
import bs.util.tool.commongui.utils.CopyFileFromCommonsIo;
import bs.util.tool.commongui.utils.FileUtils;

/**
 * 文件(夹)操作.
 */
public class FolderAndFileOperate extends GuiJPanel {

	private static final long serialVersionUID = 1L;

	/**
	 * 路径表单.
	 */
	private JTextField pathTextField = new JTextField();
	/**
	 * 目录选择.
	 */
	private JFileChooser search_fileChooser = new JFileChooser();

	/**
	 * 查找类型-文件(夹)查找.
	 */
	private final String type_search = "文件(夹)查找";
	/**
	 * 查找类型-重复文件查找.
	 */
	private final String type_repeatSearch = "重复文件查找";
	/**
	 * 查找类型-同名文件查找.
	 */
	private final String type_sameNameSearch = "同名文件查找";
	/**
	 * 查找类型-空文件(夹)查找.
	 */
	private final String type_blankSearch = "空文件(夹)查找";
	/**
	 * 查找类型.
	 */
	private final String[] types = new String[] { type_search, type_repeatSearch, type_sameNameSearch, type_blankSearch };
	/**
	 * 当前查找类型.
	 */
	private String curType = types[0];

	/**
	 * 操作类型-默认查找.
	 */
	private final String action_onlySearch = "默认查找";
	/**
	 * 操作类型-复制文件.
	 */
	private final String action_copyFile = "复制文件";
	/**
	 * 操作类型-剪切文件.
	 */
	private final String action_cutFile = "剪切文件";
	/**
	 * 操作类型-删除文件.
	 */
	private final String action_deleteFile = "删除文件";
	/**
	 * 操作类型-删除空文件夹.
	 */
	private final String action_deleteBlankFolder = "删除空文件夹";
	/**
	 * 操作类型.
	 */
	private final String[] actions = new String[] { action_onlySearch, action_copyFile, action_cutFile,
			action_deleteFile, action_deleteBlankFolder };
	/**
	 * 当前操作类型.
	 */
	private String curAction = actions[0];
	/**
	 * 操作(复制、剪切文件存放位置)表单.
	 */
	private JTextField actionTextField = new JTextField(15);
	/**
	 * 操作(复制、剪切文件存放位置)目录选择.
	 */
	private JFileChooser action_fileChooser = new JFileChooser();
	/**
	 * 操作(复制、剪切文件存放位置)目录浏览按钮.
	 */
	private JButton action_chooseButton = createJButton("浏览", "", GuiUtils.font12_cn);

	/**
	 * 常见文件类型.
	 */
	private Map<String, String> fileTypesMap = new HashMap<String, String>();
	/**
	 * 常见文件类型名称.
	 */
	private String[] fileTypeNames;
	/**
	 * 当前类型.
	 */
	private String curFileType = "";

	/**
	 * 是否包括文件,默认为true.
	 */
	private boolean containsFile = true;
	/**
	 * 是否包括文件夹,默认为true.
	 */
	private boolean containsFolder = true;
	/**
	 * 是否包括隐藏文件(夹),默认为true.
	 */
	private boolean containsHidden = true;
	/**
	 * 是否包括非隐藏文件(夹),默认为true.
	 */
	private boolean containsNotHidden = true;

	/**
	 * 是否显示文件(夹)完整路径.
	 */
	private boolean viewFullPathProp = true;
	/**
	 * 是否显示文件大小.
	 */
	private boolean viewSizeCkProp = true;
	/**
	 * 显示文件大小单位,默认M.
	 */
	private String viewSizeCkPropUnit = "M";
	/**
	 * 是否显示修改时间.
	 */
	private boolean viewModifyTimeProp = false;
	/**
	 * 是否显示隐藏属性.
	 */
	private boolean viewHiddenProp = false;

	/**
	 * 文件大小,最小表单.
	 */
	private JFormattedTextField fileSizeFromTextField = createNumberTextField();
	/**
	 * 文件大小,最大表单.
	 */
	private JFormattedTextField fileSizeToTextField = createNumberTextField();
	/**
	 * 文件大小单位,最小下拉框.
	 */
	private JComboBox fileSizeUnitFromBox = createFileSizeUnitBox(GuiUtils.font13_cn);
	/**
	 * 文件大小单位,最大下拉框.
	 */
	private JComboBox fileSizeUnitToBox = createFileSizeUnitBox(GuiUtils.font13_cn);

	/**
	 * 修改时间,开始表单.
	 */
	private JFormattedTextField modifyTimeFromTextField = createDateTextField();
	/**
	 * 修改时间,结束表单.
	 */
	private JFormattedTextField modifyTimeToTextField = createDateTextField();

	/**
	 * 文件(夹)路径包含字符表单.
	 */
	private JTextField filePathContainsTextField;
	/**
	 * 文件(夹)路径不包含字符表单.
	 */
	private JTextField filePathNotContainsTextField;
	/**
	 * 文件(夹)路径是否支持正则.
	 */
	private boolean filePathSupportRegex = false;

	/**
	 * 文件名包含字符表单.
	 */
	private JTextField fileNameContainsTextField;
	/**
	 * 文件名不包含字符表单.
	 */
	private JTextField fileNameNotContainsTextField;
	/**
	 * 文件名是否支持正则.
	 */
	private boolean fileNameSupportRegex = false;

	/**
	 * 文件夹路径包含字符表单.
	 */
	private JTextField folderPathContainsTextField;
	/**
	 * 文件夹路径不包含字符表单.
	 */
	private JTextField folderPathNotContainsTextField;
	/**
	 * 文件夹路径是否支持正则.
	 */
	private boolean folderPathSupportRegex = false;

	/**
	 * 结果文本域.
	 */
	private JTextArea resultTextArea = createJTextArea(GuiUtils.font14_un);

	/**
	 * 高级条件面板.
	 */
	private JPanel advanceConditionPanel;

	{
		// 常见文件类型
		String fileTypePropsPath = "conf/FolderAndFileOperate/filetype.properties";
		try {
			Map<String, String> propsMap = PropertiesUtils.getPropertiesMap(GuiUtils.getActualPath(fileTypePropsPath));
			List<String> propsSortAndNames = new ArrayList<String>();
			for (String key : propsMap.keySet()) {
				propsSortAndNames.add(key);
			}
			Collections.sort(propsSortAndNames); // 排序

			int expSize = propsSortAndNames.size() + 1;
			fileTypeNames = new String[expSize];
			fileTypeNames[0] = "所有";
			fileTypesMap.put(fileTypeNames[0], "");

			// 常见文件类型,按序号正排序
			for (int i = 1; i < expSize; i++) {
				String key = propsSortAndNames.get(i - 1);
				String[] keySplit = key.split("_");
				fileTypeNames[i] = keySplit.length > 1 ? key.substring(keySplit[0].length() + 1) : keySplit[0];
				fileTypesMap.put(fileTypeNames[i], propsMap.get(key));
			}
		} catch (IOException e) {
			logLoadPropertiesException(fileTypePropsPath, e);
		}
	}

	public FolderAndFileOperate() {

		// 主面板:边界布局,分North、Center两部分,North用于放置条件控件,Center是放置高级(条件)及输出
		setLayout(new BorderLayout());

		// 输入/操作
		JPanel inputPanel = new JPanel(new GridLayout(3, 1));
		add(inputPanel, BorderLayout.NORTH);

		// 目录选择/填写
		JPanel fileChooPanel = new JPanel(new BorderLayout());
		addJLabel(fileChooPanel, "  目录: ", GuiUtils.font14_cn, BorderLayout.WEST);
		JPanel pathPanel = new JPanel(new BorderLayout());
		pathPanel.add(new JPanel(), BorderLayout.NORTH);
		addJTextField(pathPanel, pathTextField, GuiUtils.font14_un, BorderLayout.CENTER);
		pathPanel.add(new JPanel(), BorderLayout.SOUTH);
		fileChooPanel.add(pathPanel, BorderLayout.CENTER);
		JPanel buttonFlowPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
		addJButton(buttonFlowPanel, "浏览", "", GuiUtils.font12_cn,
				buttonBrowseListener(search_fileChooser, pathTextField));

		// Search按钮
		addJButton(buttonFlowPanel, "查找", "", GuiUtils.font14b_cn, new MouseListener() {
			public void mouseReleased(MouseEvent event) {
				String path = pathTextField.getText().trim();
				if (!new File(path).exists()) {
					showMessage("查找目录不存在!", "警告", JOptionPane.WARNING_MESSAGE);
					return;
				}
				if (curAction.equals(action_copyFile) || curAction.equals(action_cutFile)) {
					String actionPath = actionTextField.getText().trim();
					if (!new File(actionPath).exists()) {
						showMessage("复制或剪切文件存放目录不存在!", "警告", JOptionPane.WARNING_MESSAGE);
						return;
					}
				}
				Map<String, Object> paramsMap = new HashMap<String, Object>();
				if (curType.equals(type_repeatSearch)) {
					paramsMap.put("type_repeatSearch", true);
					FileUtils.sameSizeFilesMap = new HashMap<String, List<File>>();
					FileUtils.repeatFilesMap = new HashMap<String, List<File>>();
					FileUtils.repeatFilesProp = new LinkedHashSet<String>();
				} else if (curType.equals(type_sameNameSearch)) {
					paramsMap.put("type_sameNameSearch", true);
					FileUtils.sameNameFilesMap = new HashMap<String, List<File>>();
					FileUtils.sameNameFilesProp = new LinkedHashSet<String>();
				} else if (curType.equals(type_blankSearch)) {
					paramsMap.put("type_blankSearch", true);
				}
				Long curTime = new Date().getTime();
				paramsMap.put("searchFileType", curFileType);
				paramsMap.put("containsFile", containsFile);
				paramsMap.put("containsFolder", containsFolder);
				paramsMap.put("containsHidden", containsHidden);
				paramsMap.put("containsNotHidden", containsNotHidden);
				paramsMap.put("fileSizeFrom", GuiUtils.getCountFileSizeUnit(fileSizeFromTextField.getText().trim(),
						fileSizeUnitFromBox.getSelectedItem().toString()));
				paramsMap.put("fileSizeTo", GuiUtils.getCountFileSizeUnit(fileSizeToTextField.getText().trim(),
						fileSizeUnitToBox.getSelectedItem().toString()));
				paramsMap.put("modifyTimeFrom",
						getLongFormatTime(modifyTimeFromTextField.getText().trim(), format_yyyyMMddHHmmss));
				paramsMap.put("modifyTimeTo",
						getLongFormatTime(modifyTimeToTextField.getText().trim(), format_yyyyMMddHHmmss));
				paramsMap.put("filePathContainsText", filePathContainsTextField.getText().trim());
				paramsMap.put("filePathNotContainsText", filePathNotContainsTextField.getText().trim());
				paramsMap.put("filePathSupportRegex", filePathSupportRegex);
				paramsMap.put("fileNameContainsText", fileNameContainsTextField.getText().trim());
				paramsMap.put("fileNameNotContainsText", fileNameNotContainsTextField.getText().trim());
				paramsMap.put("fileNameSupportRegex", fileNameSupportRegex);
				paramsMap.put("folderPathContainsText", folderPathContainsTextField.getText().trim());
				paramsMap.put("folderPathNotContainsText", folderPathNotContainsTextField.getText().trim());
				paramsMap.put("folderPathSupportRegex", folderPathSupportRegex);
				// 最终Search到的File,当查找类型为'重复文件查找',files最后长度为0,结果保存在FileUtils.repeatFilesProp及FileUtils.repeatFilesMap中
				List<File> files = FileUtils.getAllSubFiles(path, paramsMap);
				int cnt_action = 0;
				if (curType.equals(type_repeatSearch)) {
					List<File> repeatFiles = null;
					long cnt = 0;
					int groupCnt = FileUtils.repeatFilesProp.size();
					int size_cnt = 0;
					int f = 0;
					resultTextArea
							.append("查找方法:取出有相同大小的所有文件,比较文件大小以及前2048Byte的内容的MD5值是否一样,\n                 如果两者相同,则认为重复,否则认为不重复,有较小的误差率。\n\n\n");
					for (String prop : FileUtils.repeatFilesProp) {
						resultTextArea.append("第" + (++f) + "组:\n");
						repeatFiles = FileUtils.repeatFilesMap.get(prop);
						cnt += repeatFiles.size();
						Integer[] cntArr = printPropAndAction(curAction, repeatFiles);
						cnt_action += cntArr[0];
						size_cnt += cntArr[5];
					}
					resultTextArea.append("\n\nCount repeat group: " + groupCnt + ", files: " + cnt + ", Size: "
							+ size_cnt + "M");
					FileUtils.repeatFilesMap.clear();
					FileUtils.repeatFilesMap = null;
					FileUtils.repeatFilesProp.clear();
					FileUtils.repeatFilesProp = null;
				} else if (curType.equals(type_sameNameSearch)) {
					List<File> sameNameFiles = null;
					long cnt = 0;
					int groupCnt = FileUtils.sameNameFilesProp.size();
					int size_cnt = 0;
					int f = 0;
					resultTextArea.append("查找方法:比较文件名,不比较后缀名,查找相同文件名称的文件。\n\n\n");
					for (String prop : FileUtils.sameNameFilesProp) {
						resultTextArea.append("第" + (++f) + "组:\n");
						sameNameFiles = FileUtils.sameNameFilesMap.get(prop);
						cnt += sameNameFiles.size();
						Integer[] cntArr = printPropAndAction(curAction, sameNameFiles);
						cnt_action += cntArr[0];
						size_cnt += cntArr[5];
					}
					resultTextArea.append("\n\nCount same name group: " + groupCnt + ", files: " + cnt + ", Size: "
							+ size_cnt + "M");
					FileUtils.sameNameFilesMap.clear();
					FileUtils.sameNameFilesMap = null;
					FileUtils.sameNameFilesProp.clear();
					FileUtils.sameNameFilesProp = null;
				} else {
					Integer[] cntArr = printPropAndAction(curAction, files);
					cnt_action += cntArr[0];
					resultTextArea.append("\n\nCount: " + files.size() + ", Size: " + cntArr[5] + "M, folders: "
							+ cntArr[1] + ", files: " + cntArr[2] + ", hidden folders: " + cntArr[3]
							+ ", hidden files: " + cntArr[4]);
				}
				files.clear();
				files = null;
				if (curAction.equals(action_copyFile)) {
					resultTextArea.append(", Count Copy files: " + cnt_action);
				} else if (curAction.equals(action_cutFile)) {
					resultTextArea.append(", Count Cut files: " + cnt_action);
				} else if (curAction.equals(action_deleteFile)) {
					resultTextArea.append(", Count Delete files: " + cnt_action);
				} else if (curAction.equals(action_deleteBlankFolder)) {
					resultTextArea.append(", Count Delete blank folders: " + cnt_action);
				}
				resultTextArea.append(". Cost time:" + (new Date().getTime() - curTime) / 1000.0 + "s.");
				System.gc();
			}

			public void mousePressed(MouseEvent e) {
				resultTextArea.setText("");
			}

			public void mouseExited(MouseEvent e) {
			}

			public void mouseEntered(MouseEvent e) {
			}

			public void mouseClicked(MouseEvent e) {
			}
		});
		// 路径选择控件
		search_fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); // 仅可选择文件夹
		fileChooPanel.add(buttonFlowPanel, BorderLayout.EAST);
		inputPanel.add(fileChooPanel);

		// 条件
		JPanel conditionPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
		// 查找类型
		addJLabel(conditionPanel, " 查找类型: ", GuiUtils.font14_cn);
		addJComboBox(conditionPanel, types, GuiUtils.font13_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				curType = ((JComboBox) event.getSource()).getSelectedItem().toString();
				if (curType.equals(type_blankSearch)) {
					fileSizeFromTextField.setText("");
					fileSizeFromTextField.setEnabled(false);
					fileSizeUnitFromBox.setEnabled(false);
					fileSizeToTextField.setText("");
					fileSizeToTextField.setEnabled(false);
					fileSizeUnitToBox.setEnabled(false);
				} else {
					fileSizeFromTextField.setEnabled(true);
					fileSizeUnitFromBox.setEnabled(true);
					fileSizeToTextField.setEnabled(true);
					fileSizeUnitToBox.setEnabled(true);
				}
			}
		});

		addJLabel(conditionPanel, "   文件类型: ", GuiUtils.font14_cn);

		// 常见文件类型下拉框
		addJComboBox(conditionPanel, fileTypeNames, GuiUtils.font13_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				curFileType = fileTypesMap.get(((JComboBox) event.getSource()).getSelectedItem().toString());
			}
		});

		addJLabel(conditionPanel, " 包括:", GuiUtils.font14_cn);
		// 是否包括文件JCheckBox
		addJCheckBox(conditionPanel, "文件", true, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				JCheckBox checkBox = (JCheckBox) event.getSource();
				containsFile = checkBox.isSelected();
			}
		});
		// 是否包括文件夹JCheckBox
		addJCheckBox(conditionPanel, "文件夹", true, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				JCheckBox checkBox = (JCheckBox) event.getSource();
				containsFolder = checkBox.isSelected();
			}
		});
		// 是否包括隐藏文件(夹)JCheckBox
		addJCheckBox(conditionPanel, "隐藏文件(夹)", true, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				JCheckBox checkBox = (JCheckBox) event.getSource();
				containsHidden = checkBox.isSelected();
			}
		});
		// 是否包括隐藏文件(夹)JCheckBox
		addJCheckBox(conditionPanel, "非隐藏文件(夹)", true, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				JCheckBox checkBox = (JCheckBox) event.getSource();
				containsNotHidden = checkBox.isSelected();
			}
		});
		inputPanel.add(conditionPanel);

		JPanel viewPropAndActionPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
		addJLabel(viewPropAndActionPanel, " 操作类型: ", GuiUtils.font14_cn);
		// 操作类型下拉框
		addJComboBox(viewPropAndActionPanel, actions, GuiUtils.font13_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				curAction = ((JComboBox) event.getSource()).getSelectedItem().toString();
				if (!curAction.equals(action_onlySearch)) {
					// 将焦点转移到下一个组件,就好像此 Component 曾是焦点所有者
					((JComboBox) event.getSource()).transferFocus();
					showMessage("非查找操作务必确认不会对原文件(夹)造成意外损害!", "警告", JOptionPane.WARNING_MESSAGE);
				}
				if (curAction.equals(action_copyFile) || curAction.equals(action_cutFile)) {
					actionTextField.setEnabled(true);
					action_chooseButton.setEnabled(true);
				} else {
					actionTextField.setText("");
					actionTextField.setEnabled(false);
					action_chooseButton.setEnabled(false);
				}
			}
		});
		addJTextField(viewPropAndActionPanel, actionTextField, GuiUtils.font14_un);
		actionTextField.setEnabled(false);
		// 路径选择控件
		action_fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); // 仅可选择文件夹
		action_chooseButton.addActionListener(buttonBrowseListener(action_fileChooser, actionTextField));
		action_chooseButton.setEnabled(false);
		viewPropAndActionPanel.add(action_chooseButton);

		addJLabel(viewPropAndActionPanel, " 显示:", GuiUtils.font14_cn);
		// 是否显示文件(夹)完整路径
		addJCheckBox(viewPropAndActionPanel, "完整路径", true, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				JCheckBox checkBox = (JCheckBox) event.getSource();
				viewFullPathProp = checkBox.isSelected();
			}
		});
		// 是否显示文件大小JCheckBox
		addJCheckBox(viewPropAndActionPanel, "大小", true, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				JCheckBox checkBox = (JCheckBox) event.getSource();
				viewSizeCkProp = checkBox.isSelected();
			}
		});
		JComboBox viewSizeCkPropUnitBox = createFileSizeUnitBox(GuiUtils.font12_cn);
		viewSizeCkPropUnitBox.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				viewSizeCkPropUnit = ((JComboBox) event.getSource()).getSelectedItem().toString();
			}
		});
		viewPropAndActionPanel.add(viewSizeCkPropUnitBox);
		// 是否显示修改时间
		addJCheckBox(viewPropAndActionPanel, "修改时间", false, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				JCheckBox checkBox = (JCheckBox) event.getSource();
				viewModifyTimeProp = checkBox.isSelected();
			}
		});
		// 是否显示文件大小JCheckBox
		addJCheckBox(viewPropAndActionPanel, "隐藏属性", false, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				JCheckBox checkBox = (JCheckBox) event.getSource();
				viewHiddenProp = checkBox.isSelected();
			}
		});
		// 展开/收缩高级(条件)按钮
		addJButton(viewPropAndActionPanel, "高级", "", GuiUtils.font12_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				advanceConditionPanel.setVisible(!advanceConditionPanel.isVisible());
				getContextPanel().revalidate();
			}
		});
		inputPanel.add(viewPropAndActionPanel);

		// 高级(条件)及输出面板,使用边界布局,North为高级(条件),Center为输出
		JPanel advanceAndResultPanel = new JPanel(new BorderLayout());
		// 高级(条件
		advanceConditionPanel = new JPanel(new GridLayout(4, 1));
		advanceConditionPanel.setVisible(false);
		advanceAndResultPanel.add(advanceConditionPanel, BorderLayout.NORTH);
		// 大小条件、时间条件
		JPanel fileSizeTimePanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
		addJLabel(fileSizeTimePanel, " 文件大小: ", GuiUtils.font14_cn);
		fileSizeTimePanel.add(fileSizeFromTextField);
		fileSizeTimePanel.add(fileSizeUnitFromBox);
		addJLabel(fileSizeTimePanel, "-", GuiUtils.font14_cn);
		fileSizeTimePanel.add(fileSizeToTextField);
		fileSizeTimePanel.add(fileSizeUnitToBox);
		addJLabel(fileSizeTimePanel, "   修改时间: ", GuiUtils.font14_cn);
		fileSizeTimePanel.add(modifyTimeFromTextField);
		addJLabel(fileSizeTimePanel, "--", GuiUtils.font14_cn);
		fileSizeTimePanel.add(modifyTimeToTextField);
		advanceConditionPanel.add(fileSizeTimePanel);

		// 文件(夹)路径包含(不包含)字符
		JPanel filePathContainsPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
		addJLabel(filePathContainsPanel, " 文件/夹路径包含:", GuiUtils.font14_cn);
		filePathContainsTextField = new JTextField(24);
		addJTextField(filePathContainsPanel, filePathContainsTextField, GuiUtils.font14_un);
		addJLabel(filePathContainsPanel, "  文件/夹路径不包含:", GuiUtils.font14_cn);
		filePathNotContainsTextField = new JTextField(24);
		addJTextField(filePathContainsPanel, filePathNotContainsTextField, GuiUtils.font14_un);
		// 是否支持正则
		addJCheckBox(filePathContainsPanel, "支持正则", false, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				filePathSupportRegex = ((JCheckBox) event.getSource()).isSelected();
			}
		});
		advanceConditionPanel.add(filePathContainsPanel);

		// 文件名包含(不包含)字符
		JPanel fileNameContainsPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
		addJLabel(fileNameContainsPanel, " 文件名包含字符: ", GuiUtils.font14_cn);
		fileNameContainsTextField = new JTextField(24);
		addJTextField(fileNameContainsPanel, fileNameContainsTextField, GuiUtils.font14_un);
		addJLabel(fileNameContainsPanel, "  文件名不包含字符: ", GuiUtils.font14_cn);
		fileNameNotContainsTextField = new JTextField(24);
		addJTextField(fileNameContainsPanel, fileNameNotContainsTextField, GuiUtils.font14_un);
		// 是否支持正则
		addJCheckBox(fileNameContainsPanel, "支持正则", false, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				fileNameSupportRegex = ((JCheckBox) event.getSource()).isSelected();
			}
		});
		advanceConditionPanel.add(fileNameContainsPanel);

		// 文件夹路径包含(不包含)字符
		JPanel folderPathContainsPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
		addJLabel(folderPathContainsPanel, " 文件夹路径包含: ", GuiUtils.font14_cn);
		folderPathContainsTextField = new JTextField(24);
		addJTextField(folderPathContainsPanel, folderPathContainsTextField, GuiUtils.font14_un);
		addJLabel(folderPathContainsPanel, "  文件夹路径不包含: ", GuiUtils.font14_cn);
		folderPathNotContainsTextField = new JTextField(24);
		addJTextField(folderPathContainsPanel, folderPathNotContainsTextField, GuiUtils.font14_un);
		// 是否支持正则
		addJCheckBox(folderPathContainsPanel, "支持正则", false, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				folderPathSupportRegex = ((JCheckBox) event.getSource()).isSelected();
			}
		});
		advanceConditionPanel.add(folderPathContainsPanel);

		// 输出结果
		JPanel resultPanel = new JPanel(new BorderLayout());
		resultPanel.add(new JScrollPane(resultTextArea));
		advanceAndResultPanel.add(resultPanel, BorderLayout.CENTER);
		add(advanceAndResultPanel, BorderLayout.CENTER);
	}

	/**
	 * 输出文件属性及根据操作类型操作文件,返回值表示复制文件/剪切文件/删除文件/删除文件夹的数目,查找到文件夹总数,查找到文件总数,
	 * 查找到隐藏文件夹总数,查找到隐藏文件总数.
	 */
	private Integer[] printPropAndAction(String action, List<File> files) {
		int cnt_action = 0;
		int cnt_folders = 0;
		int cnt_files = 0;
		int cnt_folders_hidden = 0;
		int cnt_files_hidden = 0;
		long cnt_length = 0;
		for (File file : files) {
			if (file.isDirectory()) {
				cnt_folders++;
				if (file.isHidden()) {
					cnt_folders_hidden++;
				}
			} else {
				cnt_files++;
				cnt_length += file.length();
				if (file.isHidden()) {
					cnt_files_hidden++;
				}
			}
			if (viewFullPathProp) {
				resultTextArea.append(file.getAbsolutePath());
			} else {
				resultTextArea.append(file.getName());
			}
			if (viewSizeCkProp && !file.isDirectory()) {
				resultTextArea.append("   Size: ");
				if (viewSizeCkPropUnit.equals(GuiUtils.FileSize_M)) {
					resultTextArea.append(format_double_3.format(file.length() / 1024.0 / 1024.0) + "M");
				} else if (viewSizeCkPropUnit.equals(GuiUtils.FileSize_KB)) {
					resultTextArea.append(format_double_3.format(file.length() / 1024.0) + "KB");
				} else if (viewSizeCkPropUnit.equals(GuiUtils.FileSize_Byte)) {
					resultTextArea.append(file.length() + "Byte");
				} else if (viewSizeCkPropUnit.equals(GuiUtils.FileSize_G)) {
					resultTextArea.append(format_double_6.format(file.length() / 1024.0 / 1024.0 / 1024.0) + "G");
				}
			}
			if (viewModifyTimeProp) {
				resultTextArea.append("   ModifyTime: " + format_yyyyMMddHHmmss.format(new Date(file.lastModified())));
			}
			if (viewHiddenProp) {
				resultTextArea.append("   Hidden: " + (file.isHidden() ? "Y" : "N"));
			}
			resultTextArea.append("\n");
			if (!curAction.equals(action_onlySearch)) {
				if (!file.isDirectory()) {
					if (curAction.equals(action_copyFile)) {
						// 复制文件
						copyFile(file);
						cnt_action++;
					} else if (curAction.equals(action_cutFile)) {
						// 剪切文件
						copyFile(file); // 先复制文件
						file.delete(); // 然后删除文件
						cnt_action++;
					} else if (curAction.equals(action_deleteFile)) {
						file.delete(); // 删除文件
						cnt_action++;
					}
				} else if (curAction.equals(action_deleteBlankFolder) && file.listFiles() != null
						&& file.listFiles().length == 0) {
					file.delete(); // 删除空文件夹
					cnt_action++;
				}
			}
		}
		return new Integer[] { cnt_action, cnt_folders, cnt_files, cnt_folders_hidden, cnt_files_hidden,
				(int) (cnt_length / 1024 / 1024) };
	}

	/**
	 * 复制文件.
	 */
	private void copyFile(File srcFile) {
		String actionPath = actionTextField.getText().trim();
		try {
			CopyFileFromCommonsIo.copyFile(srcFile, new File(actionPath + "/" + srcFile.getName()));
		} catch (IOException e) {
			showExceptionMessage(e);
		}
	}
}


text:
package uk.me.eddies.lib.neuron.neuralnet.type.feedforward;

import static java.util.stream.Collectors.toCollection;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import uk.me.eddies.lib.neuron.neuralnet.ActivationFunction;
import uk.me.eddies.lib.neuron.neuralnet.ComputedNeuron;
import uk.me.eddies.lib.neuron.neuralnet.Connection;
import uk.me.eddies.lib.neuron.neuralnet.Neuron;

public class OutputLayerTest {

	@Mock private Layer previousLayer;
	@Mock private Neuron prevNeuron1;
	@Mock private Neuron prevNeuron2;
	@Mock private ActivationFunction activationFunction;

	private OutputLayer systemUnderTest;

	private Layer result;

	@Before
	public void setUp() {
		initMocks(this);
		when(previousLayer.getNeurons()).thenReturn(Arrays.asList(prevNeuron1, prevNeuron2));

		systemUnderTest = new OutputLayer(2, activationFunction);
		result = systemUnderTest.buildLayer(Optional.of(previousLayer));
	}

	@Test(expected = NullPointerException.class)
	public void shouldFailWithNullPreviousLayerContainer() {
		systemUnderTest.buildLayer(null);
	}

	@Test(expected = NullPointerException.class)
	public void shouldFailWithNullActivationFunction() {
		new OutputLayer(2, null);
	}

	@Test
	public void shouldCreateNeurons() {
		assertThat(result.getNeurons(), contains(Arrays.asList(
				instanceOf(ComputedNeuron.class),
				instanceOf(ComputedNeuron.class))));
	}

	@Test
	public void shouldCreateNeuronsLinkedToPreviousNeurons() {
		List<Neuron> neurons = new ArrayList<>(result.getNeurons());
		List<Connection> neuron1Connections = new ArrayList<>(neurons.get(0).getConnections());
		List<Connection> neuron2Connections = new ArrayList<>(neurons.get(1).getConnections());

		assertThat(neuron1Connections, hasSize(2));
		assertThat(neuron1Connections.get(0).getConnectee(), sameInstance(prevNeuron1));
		assertThat(neuron1Connections.get(1).getConnectee(), sameInstance(prevNeuron2));
		assertThat(neuron2Connections, hasSize(2));
		assertThat(neuron2Connections.get(0).getConnectee(), sameInstance(prevNeuron1));
		assertThat(neuron2Connections.get(1).getConnectee(), sameInstance(prevNeuron2));
	}

	@Test
	public void shouldConsolidateConnectionsFromAllNeurons() {
		Collection<Connection> expected = result.getNeurons().stream()
				.flatMap(n -> n.getConnections().stream())
				.collect(toCollection(LinkedHashSet::new));
		assertThat(expected, hasSize(4));

		assertThat(new LinkedHashSet<>(result.getConnections()), equalTo(expected));
	}

	@Test
	public void shouldHaveNoInputInterface() {
		assertThat(result.getInputInterface(), equalTo(Optional.empty()));
	}

	@Test
	public void shouldHaveOutputInterfaceLinkedToNeurons() {
		when(prevNeuron1.getValue()).thenReturn(5d);
		when(prevNeuron2.getValue()).thenReturn(10d);
		when(activationFunction.applyAsDouble(5d)).thenReturn(6d);
		when(activationFunction.applyAsDouble(10d)).thenReturn(11d);
		Iterator<Connection> connectionIt = result.getNeurons().stream()
				.flatMap(n -> n.getConnections().stream()).iterator();
		connectionIt.next().setWeight(1d); // 1 -> 1
		connectionIt.next().setWeight(0d); // 2 -> 1
		connectionIt.next().setWeight(0d); // 1 -> 2
		connectionIt.next().setWeight(1d); // 2 -> 2

		List<Double> results = result.getOutputInterface().get().getValues();

		assertThat(results, contains(Arrays.asList(equalTo(6d), equalTo(11d))));
	}
}


text:
var DatabankObject = require("databank").DatabankObject,
    Step = require("step"),
    _ = require("underscore"),
    wf = require("webfinger"),
    ActivityObject = require("./activityobject").ActivityObject,
    URLMaker = require("../urlmaker").URLMaker;

var Person = DatabankObject.subClass("person", ActivityObject);

Person.schema = {pkey: "id",
                 fields: ["displayName",
                          "image",
                          "published",
                          "updated",
                          "url",
                          "_uuid"],
                 indices: ["_uuid"]
                };

Person.pkey = function() {
    return "id";
};

Person.beforeCreate = function(props, callback) {

    Step(
        function() {
            ActivityObject.beforeCreate.apply(Person, [props, this]);
        },
        function(err, props) {
            if (err) {
                callback(err, null);
            } else {
                // Are we creating a local user?
                // XXX: watch out for tricks!

                if (_.has(props, "_user") && props._user) {

                    if (!_.has(props, "links")) {
                        props.links = {};
                    }

                    props.links["activity-inbox"] = {
                        href: URLMaker.makeURL("api/user/" + props.preferredUsername + "/inbox")
                    };

                    props.links["activity-outbox"] = {
                        href: URLMaker.makeURL("api/user/" + props.preferredUsername + "/feed")
                    };

                    // NB: overwrites self-link in ActivityObject.beforeCreate

                    props.links["self"] = {
                        href: URLMaker.makeURL("api/user/" + props.preferredUsername + "/profile")
                    };

                    // Add the feeds sub-elements

                    Person.ensureFeeds(props, props.preferredUsername);

                    // Trim them if they existed before

                    ActivityObject.trimCollection(props, "followers");
                    ActivityObject.trimCollection(props, "following");
                    ActivityObject.trimCollection(props, "favorites");
                    ActivityObject.trimCollection(props, "lists");
                }

                callback(null, props);
            }
        }
    );
};

Person.prototype.afterGet = function(callback) {

    var person = this;

    ActivityObject.trimCollection(person, "followers");
    ActivityObject.trimCollection(person, "following");
    ActivityObject.trimCollection(person, "favorites");
    ActivityObject.trimCollection(person, "lists");

    callback(null);
};

Person.prototype.beforeUpdate = function(props, callback) {
    var person = this;

    Step(
        function() {
            ActivityObject.prototype.beforeUpdate.apply(person, [props, this]);
        },
        function(err, props) {
            if (err) {
                callback(err, null);
            } else {
                // Trim them if they existed before

                ActivityObject.trimCollection(props, "followers");
                ActivityObject.trimCollection(props, "following");
                ActivityObject.trimCollection(props, "favorites");
                ActivityObject.trimCollection(props, "lists");

                callback(null, props);
            }
        }
    );
};

Person.prototype.beforeSave = function(callback) {

    var person = this;

    Step(
        function() {
            ActivityObject.prototype.beforeSave.apply(person, [this]);
        },
        function(err) {
            if (err) {
                callback(err);
            } else {
                // Trim them if they existed before

                ActivityObject.trimCollection(person, "followers");
                ActivityObject.trimCollection(person, "following");
                ActivityObject.trimCollection(person, "favorites");
                ActivityObject.trimCollection(person, "lists");

                callback(null);
            }
        }
    );
};

Person.ensureFeeds = function(obj, nickname) {
    var feeds = ["followers", "following", "favorites"];
    _.each(feeds, function(feed) {
        if (!_.has(obj, feed)) {
            obj[feed] = {
                url: URLMaker.makeURL("/api/user/"+nickname+"/"+feed)
            };
        }
    });
    if (!_.has(obj, "lists")) {
        obj.lists = {
            url: URLMaker.makeURL("/api/user/"+nickname+"/lists/person")
        };
    }
};

Person.prototype.followersURL = function(callback) {
    var person = this,
        User = require("./user").User;

    Step(
        function() {
            User.fromPerson(person.id, this);
        },
        function(err, user) {
            if (err) {
                callback(err, null);
            } else if (!user) {
                callback(null, null);
            } else {
                callback(null, URLMaker.makeURL("api/user/" + user.nickname + "/followers"));
            }
        }
    );
};

Person.prototype.getInbox = function(callback) {

    var person = this,
        User = require("./user").User;

    // XXX: use person.links to find one with "activity-inbox" rel

    Step(
        function() {
            User.fromPerson(person.id, this);
        },
        function(err, user) {
            if (err) throw err;
            if (user) {
                callback(null, URLMaker.makeURL("api/user/" + user.nickname + "/inbox"));
            } else if (person.id.substr(0, 5) == "acct:") {
                wf.webfinger(person.id.substr(5), this);
            } else {
                // XXX: try LRDD for http: and https: URIs
                // XXX: try LRDD for http: and https: URIs
                // XXX: try getting Link or <link> values from person.url
                callback(new Error("Can't get inbox for " + person.id), null);
            }
        },
        function(err, jrd) {
            var inboxes;
            if (err) {
                callback(err, null);
                return;
            } else if (!_(jrd).has("links") ||
                       !_(jrd.links).isArray()) {
                callback(new Error("Can't get inbox for " + person.id), null);
                return;
            } else {
                // Get the inboxes
                inboxes = jrd.links.filter(function(link) {
                    return (link.hasOwnProperty("rel") &&
                            link.rel == "activity-inbox" &&
                            link.hasOwnProperty("href"));
                });

                if (inboxes.length === 0) {
                    callback(new Error("Can't get inbox for " + person.id), null);
                    return;
                }

                callback(null, inboxes[0].href);
            }
        }
    );
};

Person.prototype.expandFeeds = function(callback) {
    var person = this,
        user;

    // These are inapplicable feeds; hide them

    delete person.likes;
    delete person.replies;

    Step(
        function() {
            var User = require("./user").User;
            User.fromPerson(person.id, this);
        },
        function(err, result) {
            var cb;
            if (err) throw err;
            if (!result) {
                callback(null);
                return;
            }
            user = result;
            user.followerCount(this.parallel());
            user.followingCount(this.parallel());
            user.favoritesCount(this.parallel());
            // Blech.
            cb = this.parallel();
            user.getLists(Person.type, function(err, str) {
                if (err) {
                    cb(err, null);
                } else {
                    str.count(cb);
                }
            });
        },
        function(err, followers, following, favorites, lists) {
            if (err) {
                callback(err);
            } else {
                // Make sure all feed objects exist
                Person.ensureFeeds(person, user.nickname);

                person.followers.totalItems = followers;
                person.following.totalItems = following;
                person.favorites.totalItems = favorites;
                person.lists.totalItems     = lists;

                // Make sure there are no actual items in there
                delete person.followers.items;
                delete person.following.items;
                delete person.favorites.items;
                delete person.lists.items;

                callback(null);
            }
        }
    );
};

Person.prototype.sanitize = function() {
    if (this._user) {
        delete this._user;
    }
    ActivityObject.prototype.sanitize.apply(this);
};

exports.Person = Person;