private void exportNode(PropWriter w, DynamicNode node, boolean includeVar, File dir) {
    p("doing node: " + node);
    String[] visualOnlyProps = new String[] {"x", "y", "width", "height"};
    List<String> resizeOnlyProps = Arrays.asList("width", "height");

    if (includeVar) {
      w.newObj(node.getId(), AminoAdapter.getScriptClass(node));
    } else {
      w.newObj(AminoAdapter.getScriptClass(node));
    }
    w.indent();
    for (Property prop : node.getProperties()) {
      if (!AminoAdapter.shouldExportProperty(node, prop)) continue;
      p(
          "writing: "
              + prop.getName()
              + " "
              + prop.getRawValue()
              + " exported = "
              + prop.isExported());
      String key = prop.getName();
      if (key.equals("translateX")) key = "x";
      if (key.equals("translateY")) key = "y";
      if (!node.isVisual() && Arrays.asList(visualOnlyProps).contains(key)) continue;
      if (key.equals("width") && !canResizeHorizontal(node)) continue;
      if (key.equals("height") && !canResizeVertical(node)) continue;
      if (key.equals("draggable")) continue;
      if (key.equals("src") && node.getName().equals("Image")) {
        try {
          URL srcURL = new URL(prop.getStringValue());
          File dstFile = calcUniqueImageName(dir);
          StringUtils.copyFile(srcURL, dstFile);
          w.prop(key, dstFile.getName());
          continue;
        } catch (IOException e) {
          e
              .printStackTrace(); // To change body of catch statement use File | Settings | File
                                  // Templates.
        }
      }
      w.prop(key, prop.getRawValue());
    }

    for (SketchNode child : node.children()) {
      w.p(".add(");
      exportNode(w, (DynamicNode) child, false, dir);
      w.p(")");
    }
    if (includeVar) {
      w.p(";");
    }
    w.outdent();
  }
  @Override
  public void execute() {

    if (USE_OMETA) {
      try {
        exportWithOmeta();
      } catch (Exception e) {
        e.printStackTrace();
      }
      return;
    }
    try {
      File dir = new File("/Users/josh/projects/Leo/t2");
      File html = new File(dir, "foo.html");
      File templatedir = new File("resources/");
      if (useRandomFile) {

      } else {

        // get a file to write to
        if (document.getExportFile() != null) {
          html = document.getExportFile();
          dir = html.getParentFile();
        } else {
          java.awt.FileDialog fd = new java.awt.FileDialog((Frame) null);
          fd.setMode(FileDialog.SAVE);
          fd.setVisible(true);
          if (fd.getFile() == null) {
            return;
          }
          String filename = fd.getFile();
          if (!filename.toLowerCase().endsWith(".html")) {
            filename += ".html";
          }
          html = new File(fd.getDirectory(), filename);
          dir = html.getParentFile();
        }
      }

      // File file = File.createTempFile("foo",".html");
      // file.deleteOnExit();
      StringWriter treeContent = new StringWriter();
      PrintWriter treeOut = new PrintWriter(treeContent);
      PropWriter treeWriter = new PropWriter(treeOut);
      StringWriter setupContent = new StringWriter();
      for (Layer layer : page.children()) {
        treeWriter.p("//layer");
        treeWriter.indent();
        for (SketchNode node : layer.children()) {
          DynamicNode dnode = (DynamicNode) node;
          exportNode(treeWriter, dnode, true, dir);
          if (node.isVisual() && AminoAdapter.shouldAddToScene(node, document.getBindings())) {
            setupContent.append("root.add(" + node.getId() + ");\n");
          }
          if (AminoAdapter.useSetup(dnode)) {
            setupContent.append(node.getId() + ".setup(root);\n");
          }
          doExtensions(setupContent, dnode);
        }
        treeWriter.outdent();
      }

      for (Binding binding : document.getBindings()) {
        exportBinding(new PrintWriter(setupContent), binding);
      }

      treeOut.close();
      setupContent.close();

      Map<String, String> subs = new HashMap<String, String>();
      subs.put("tree", treeContent.toString());
      subs.put("setup", setupContent.toString());

      if (!html.exists()) {
        StringUtils.applyTemplate(new File(templatedir, "index_template.html"), html, subs);
      }
      File js = new File(dir, "generated.js");
      StringUtils.applyTemplate(new File(templatedir, "generated_template.js"), js, subs);
      StringUtils.copyFile(new File(templatedir, "amino.js"), new File(dir, "amino.js"));
      StringUtils.copyFile(new File(templatedir, "jquery.js"), new File(dir, "jquery.js"));
      StringUtils.copyFile(new File(templatedir, "controls.js"), new File(dir, "controls.js"));

      File trimfile = new File("/Users/josh/");
      String partialPath =
          dir.getAbsolutePath().substring((int) trimfile.getAbsolutePath().length());
      OSUtil.openBrowser("http://localhost/~josh/" + partialPath + "/" + html.getName());

      document.setExportFile(html);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  private void exportBinding(PrintWriter out, Binding binding) {
    if (AminoAdapter.shouldExportAsSetter(binding)) {
      String prop = binding.getTargetProperty().getName();
      out.println(
          binding.getTarget().getId()
              + ".set"
              + prop.substring(0, 1).toUpperCase()
              + prop.substring(1)
              + "("
              + binding.getSource().getId()
              + ");");
      return;
    }

    if (AminoAdapter.shouldExportAsAdder(binding)) {
      out.print(binding.getTarget().getId() + ".add(");
      out.print(binding.getSource().getId());
      out.println(");");
      return;
    }

    if (AminoAdapter.shouldExportAsTrigger(binding)) {
      out.println(binding.getSource().getId() + ".setCallback(" + "function(){\n");
      out.println("    " + binding.getTarget().getId() + ".execute();");
      out.println("});");
      return;
    }

    if (binding.getSource().getName().equals("ListView")) {
      if (binding.getSourceProperty().isProxy()) {
        p("it's a proxy! " + binding.getSourceProperty().getName());
        p("master = " + binding.getSourceProperty().getMasterProperty());
        String n = binding.getTargetProperty().getName();
        String setterName = "set" + n.substring(0, 1).toUpperCase() + n.substring(1);
        out.println(
            binding.getSource().getId()
                + ".listen(function(e){\n"
                + "  var val = e.getSelectedObject()."
                + binding.getSourceProperty().getName()
                + ";\n"
                + "  "
                + binding.getTarget().getId()
                + "."
                + setterName
                + "(val);\n"
                + "});\n");
        return;
      }
    }

    out.println(
        "var binder = new Binder()"
            + ".set("
            + binding.getSource().getId()
            + ",'"
            + binding.getSourceProperty().getName()
            + "',"
            + binding.getTarget().getId()
            + ",'"
            + binding.getTargetProperty().getName()
            + "');\n"
            + "engine.addAnim(binder);\n"
            + "binder.start();\n");
  }