protected Property parse(String line, ValueFactories factories, PropertyFactory propFactory) {
    if (line.length() == 0) return null; // blank line
    char firstChar = line.charAt(0);
    if (firstChar == '#') return null; // comment line
    if (firstChar == ' ') return null; // ignore line
    Matcher matcher = PROPERTY_PATTERN.matcher(line);
    if (!matcher.matches()) {
      // It should be an empty multi-valued property, and the line consists only of the name ...
      Name name = factories.getNameFactory().create(decoder.decode(line));
      return propFactory.create(name);
    }

    String nameString = decoder.decode(matcher.group(1));
    String typeString = matcher.group(2);
    String valuesString = matcher.group(4);

    Name name = factories.getNameFactory().create(nameString);
    PropertyType type = PropertyType.valueFor(typeString);

    Pattern pattern = VALUE_PATTERN;
    ValueFactory<?> valueFactory = factories.getValueFactory(type);
    boolean binary = false;
    boolean decode = false;
    if (type == PropertyType.STRING) {
      // Parse the double-quoted value(s) ...
      pattern = STRING_VALUE_PATTERN;
      decode = true;
    } else if (type == PropertyType.BINARY) {
      binary = true;
    }
    Matcher valuesMatcher = pattern.matcher(valuesString);
    List<Object> values = new ArrayList<Object>();
    while (valuesMatcher.find()) {
      String valueString = valuesMatcher.group(1);
      if (binary) {
        // The value is a hexadecimal-encoded byte array ...
        byte[] binaryValue = StringUtil.fromHexString(valueString);
        Object value = valueFactory.create(binaryValue);
        values.add(value);
      } else {
        if (decode) valueString = quoter.decode(valueString);
        Object value = valueFactory.create(valueString);
        values.add(value);
      }
    }
    if (values.isEmpty()) return null;
    return propFactory.create(name, type, values);
  }
 /**
  * Get the graph {@link Property property} for the supplied JCR property representation.
  *
  * @param jcrProperty the JCR property; may not be null
  * @return the graph property
  * @throws RepositoryException if there is an error working with the session
  */
 public Property propertyFor(javax.jcr.Property jcrProperty) throws RepositoryException {
   // Get the values ...
   Object[] values = null;
   if (jcrProperty.getDefinition().isMultiple()) {
     Value[] jcrValues = jcrProperty.getValues();
     values = new Object[jcrValues.length];
     for (int i = 0; i < jcrValues.length; i++) {
       values[i] = convert(jcrValues[i], jcrProperty);
     }
   } else {
     values = new Object[] {convert(jcrProperty.getValue(), jcrProperty)};
   }
   // Get the name, and then create the property ...
   Name name = nameFactory.create(jcrProperty.getName());
   return propertyFactory.create(name, values);
 }
 public Property propertyFor(Name name, Object... values) {
   return propertyFactory.create(name, values);
 }