docs: public static RedwoodConfiguration parse(Properties props){
      Set<String> used = new HashSet<String>();
      //--Construct Pipeline
      //(handlers)
      Redwood.ConsoleHandler console = get(props,"log.toStderr","false",used).equalsIgnoreCase("true") ? Redwood.ConsoleHandler.err() : Redwood.ConsoleHandler.out();
      VisibilityHandler visibility = new VisibilityHandler();
      RepeatedRecordHandler repeat = null;
      //(initialize pipeline)
      RedwoodConfiguration config = new RedwoodConfiguration().clear().rootHandler(visibility);
      //(collapse)
      String collapseSetting = get(props,"log.collapse","none",used);
      if(collapseSetting.equalsIgnoreCase("exact")){
        repeat = new RepeatedRecordHandler(RepeatedRecordHandler.EXACT);
        config = config.handler(visibility,repeat);
      } else if(collapseSetting.equalsIgnoreCase("approximate")){
        repeat = new RepeatedRecordHandler(RepeatedRecordHandler.APPROXIMATE);
        config = config.handler(visibility, repeat);
      } else if(collapseSetting.equalsIgnoreCase("none")){
        //do nothing
      } else {
        throw new IllegalArgumentException("Unknown collapse type: " + collapseSetting);
      }
      //--Console
      config.handler(repeat == null ? visibility : repeat, console);
      //((track color))
      console.trackColor = Color.valueOf(get(props,"log.console.trackColor","NONE",used).toUpperCase());
      console.trackStyle = Style.valueOf(get(props,"log.console.trackStyle","NONE",used).toUpperCase());
      //((other colors))
      for(Object propAsObj : props.keySet()) {
        String prop = propAsObj.toString();
        // color
        Matcher m = consoleColor.matcher(prop);
        if(m.find()){
          String channel = m.group(1);
          console.colorChannel(channel, Color.valueOf(get(props,prop,"NONE",used)));
        }
        // style
        m = consoleStyle.matcher(prop);
        if(m.find()){
          String channel = m.group(1);
          console.styleChannel(channel, Style.valueOf(get(props,prop,"NONE",used)));
        }
      }
      //((random colors))
      console.setColorChannels(Boolean.parseBoolean(get(props, "log.console.colorChannels", "false", used)));
      //--File
      String logFilename = get(props,"log.file",null,used);
      if(logFilename != null){
        Redwood.FileHandler file = new Redwood.FileHandler(logFilename);
        config.handler(repeat == null ? visibility : repeat, file);
        //((track colors))
        file.trackColor = Color.valueOf(get(props,"log.file.trackColor","NONE",used).toUpperCase());
        file.trackStyle = Style.valueOf(get(props,"log.file.trackStyle","NONE",used).toUpperCase());
        //((other colors))
        for(Object propAsObj : props.keySet()) {
          String prop = propAsObj.toString();
          // color
          Matcher m = fileColor.matcher(prop);
          if(m.find()){
            String channel = m.group(1);
            file.colorChannel(channel, Color.valueOf(get(props,prop,"NONE",used)));
          }
          // style
          m = fileStyle.matcher(prop);
          if(m.find()){
            String channel = m.group(1);
            file.styleChannel(channel, Style.valueOf(get(props,prop,"NONE",used)));
          }
        }
        //((random colors))
        file.setColorChannels(Boolean.parseBoolean(get(props,"log.file.colorChannels","false",used)));
      }
      
      //--System Streams
      if(get(props,"log.captureStreams","false",used).equalsIgnoreCase("true")){
        config = config.captureStreams();
      }
      if(get(props,"log.captureStdout","false",used).equalsIgnoreCase("true")){
        config = config.captureStdout();
      }
      if(get(props,"log.captureStderr","false",used).equalsIgnoreCase("true")){
        config = config.captureStderr();
      }
      //--Neat exit
      if(get(props,"log.neatExit","false",used).equalsIgnoreCase("true")){
        config = config.neatExit();
      }
      String channelsToShow = get(props,"log.showOnlyChannels",null,used);
      String channelsToHide = get(props,"log.hideChannels",null,used);
      if (channelsToShow != null && channelsToHide != null) {
        throw new IllegalArgumentException("Can't specify both log.showOnlyChannels and log.hideChannels");
      }
      //--Channel visibility
      if (channelsToShow != null) {
        config = config.showOnlyChannels(channelsToShow.split(","));
      } else if (channelsToHide != null) {
        config = config.hideChannels(channelsToHide.split(","));
      }
      //--Error Check
      for(Object propAsObj : props.keySet()) {
        String prop = propAsObj.toString();
        if(prop.startsWith("log.") && !used.contains(prop)){
          throw new IllegalArgumentException("Could not find Redwood log property: " + prop);
        }
      }
      //--Return
      return config;
    }