<commit_before>package clasp

import scala.collection.mutable.MutableList

import scala.collection.mutable.ListBuffer
import scala.sys.process._
import scala.language.postfixOps

import scala.concurrent._
import scala.concurrent.duration._

import org.slf4j.LoggerFactory

import com.typesafe.config.ConfigFactory

import akka.actor._
import akka.pattern.Patterns.ask
import akka.util.Timeout
import java.util.concurrent.TimeUnit

import clasp.core._
import clasp.core.sdktools.sdk
import clasp.core.sdktools.EmulatorOptions
import java.io.File

/*
 * Example of using Clasp. The App will be packaged and deployed to both the server and 
 * the client machines. Note that you should never be the one specifying --client on the 
 * command line. Starting the server will, with proper configuration parameters, start all
 * of the worker machines. The corollary is that stopping the server is a graceful operation
 * and all of the worker machines will be properly shutdown as soon as they are done processing
 * their current message. If your messages are huge this might take a while, but this is 
 * much better than logging into each machine and force killing all of the processes associated
 * with running clasp. If you manually shutdown instead of using the graceful operation then 
 * you had better know how to clean up the proper processes, because the system may refuse to 
 * restart on any computers that have an incorrect start state!
 */
object ClaspRunner extends App {
  // If you would like logging on remote machines(all workers), then use these logging methods
  // in your codebase. The logs will (eventually) be pulled back to the master, so that you don't
  // need to manually aggregrate your logs
  lazy val log = LoggerFactory.getLogger(getClass())
  import log.{error, debug, info, trace}

  // Used to parse the command line arguments
  val conf = new ClaspConf(args)

  // TODO: Add a way for emulator options to be nonuniform?
  // Setup some options for the emulator
  val opts = new EmulatorOptions
  opts.noWindow = true
  
  // Create a new instance of the framework. There should be at least one instance of Clasp
  // started per computer in your cluster, although you should probably let the master handle
  // starting all of the workers
  if (conf.client()) 
    new ClaspClient(conf, opts)
  else {
    var clasp = new ClaspMaster(conf)

    // TODO should we update the system so the user extends "ClaspServer" and only writes this 
    // part of the codebase? Everything above seems like boilerplate code
    // TODO: We shouldn't have to sleep like this.
    //       Add an option to wait until all emulators are alive,
    //       but not necessarily entirely booted.
    // @Brandon - this is a great idea for the object-level API! Something like waitForEmulators(10)
    // that will be called when there are 10 emulators alive and ready. Or perhaps that's how we build
    // the main action loop - have a waitForEmulator(new Task() { // do something with emulator here })
    //Thread.sleep(100000)

    printf("Testing callback abilities")
  
    import ExecutionContext.Implicits.global
    // Any logging done inside the callbcak will show up in the remote host nohup file
    // Any exceptions thrown will be delivered to onFailure handler
    val f = clasp.register_on_new_emulator( (emu: Emulator) => {
        var result = scala.collection.mutable.Map[String, Any]()
        info("About to install")
        result("serialID") = emu.serialID
        result("node") = "hostname".!!.stripLineEnd
        
        sdk.install_package(emu.serialID,"examples/antimalware/Profiler.apk")
        info("installed")
        result.toMap
      }
    )
    f onSuccess {
      case data => info(s"""Emulator Task completed successfully on Node ${data("node")}, emulator ${data("serialID")}""")
    }
    f onFailure {
      case t => error(s"Future failed due to ${t.getMessage}")
    }

    //Thread.sleep(20000)
    //clasp.kill
  } // End of clasp master logic
}
 

/* TODO make it possible to support sending EmulatorOptions across the
 * network and starting emulators with different options
 */
class ClaspClient(val conf: ClaspConf, val emuOpts: EmulatorOptions) {
  val ip = conf.ip()
  val clientConf = ConfigFactory
    .parseString(s"""akka.remote.netty.hostname="$ip"""")<commit_msg>Clasp: Formatting.<commit_after>package clasp

import scala.collection.mutable.MutableList

import scala.collection.mutable.ListBuffer
import scala.sys.process._
import scala.language.postfixOps

import scala.concurrent._
import scala.concurrent.duration._

import org.slf4j.LoggerFactory

import com.typesafe.config.ConfigFactory

import akka.actor._
import akka.pattern.Patterns.ask
import akka.util.Timeout
import java.util.concurrent.TimeUnit

import clasp.core._
import clasp.core.sdktools.sdk
import clasp.core.sdktools.EmulatorOptions
import java.io.File

/*
 * Example of using Clasp. The App will be packaged and deployed to both the server and 
 * the client machines. Note that you should never be the one specifying --client on the 
 * command line. Starting the server will, with proper configuration parameters, start all
 * of the worker machines. The corollary is that stopping the server is a graceful operation
 * and all of the worker machines will be properly shutdown as soon as they are done processing
 * their current message. If your messages are huge this might take a while, but this is 
 * much better than logging into each machine and force killing all of the processes associated
 * with running clasp. If you manually shutdown instead of using the graceful operation then 
 * you had better know how to clean up the proper processes, because the system may refuse to 
 * restart on any computers that have an incorrect start state!
 */
object ClaspRunner extends App {
  // If you would like logging on remote machines(all workers), then use these logging methods
  // in your codebase. The logs will (eventually) be pulled back to the master, so that you don't
  // need to manually aggregrate your logs
  lazy val log = LoggerFactory.getLogger(getClass())
  import log.{error, debug, info, trace}

  // Used to parse the command line arguments
  val conf = new ClaspConf(args)

  // TODO: Add a way for emulator options to be nonuniform?
  // Setup some options for the emulator
  val opts = new EmulatorOptions
  opts.noWindow = true
  
  // Create a new instance of the framework. There should be at least one
  // instance of Clasp started per computer in your cluster, although you
  // should probably let the master handle starting all of the workers.
  if (conf.client()) 
    new ClaspClient(conf, opts)
  else {
    var clasp = new ClaspMaster(conf)
    printf("Testing callback abilities")
  
    import ExecutionContext.Implicits.global
    // Any logging done inside the callback will show up in the remote host
    // nohup file Any exceptions thrown will be delivered to onFailure handler.
    val f = clasp.register_on_new_emulator( (emu: Emulator) => {
        var result = scala.collection.mutable.Map[String, Any]()
        info("About to install")
        result("serialID") = emu.serialID
        result("node") = "hostname".!!.stripLineEnd
        
        sdk.install_package(emu.serialID,"examples/antimalware/Profiler.apk")
        info("installed")
        result.toMap
      }
    )
    f onSuccess {
      case data => info(s"""Emulator Task completed successfully on Node ${data("node")}, emulator ${data("serialID")}""")
    }
    f onFailure {
      case t => error(s"Future failed due to ${t.getMessage}")
    }
    Thread.sleep(25000)
    clasp.kill
  } // End of clasp master logic
}
 

/* TODO make it possible to support sending EmulatorOptions across the
 * network and starting emulators with different options
 */
class ClaspClient(val conf: ClaspConf, val emuOpts: EmulatorOptions) {
  val ip = conf.ip()
  val clientConf = ConfigFactory
    .parseString(s"""akka.remote.netty.hostname="$ip"""")
{'fraction_non_alphanumeric': 0.07592407592407592, 'fraction_numerical': 0.0027472527472527475, 'mean_word_length': 3.494388327721661, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6109764', 'n_tokens_mistral': 2185, 'n_tokens_neox': 2115, 'n_words': 927}