func main() {
	var shops golib.StringSlice
	parallel_orders := flag.Uint("orders", 20, "Number of open orders running at the same time")
	bank := flag.String("bank", "localhost:9001", "Bank endpoint")
	timeout := flag.Duration("timeout", 0, "Timeout for automatically stopping load generation")
	flag.Var(&shops, "shop", "Shop endpoint(s)")
	flag.Parse()
	if len(shops) == 0 {
		log.Fatalln("Specify at least one -shop")
	}

	golib.ConfigureOpenFilesLimit()

	orders := OrderPool{
		ParallelOrders: *parallel_orders,
		Bank:           *bank,
		Shops:          shops,
		User:           "******",
	}
	orders.Start()

	onInterrupt(orders.Terminate)
	if *timeout > 0 {
		services.L.Warnf("Terminating automatically after %v", timeout)
		time.AfterFunc(*timeout,
			func() {
				services.L.Warnf("Timer of %v expired. Terminating...", timeout)
				orders.Terminate()
			})
	}
	orders.Wait()
	orders.PrintStats()
}
func main() {
	addr := flag.String("listen", "0.0.0.0:9003", "Endpoint address")
	redisEndpoint := flag.String("redis", "127.0.0.1:6379", "Redis endpoint")
	services.ParseBalanceEndpointsFlags()
	flag.Parse()
	services.ParseLoadBalanceConfig()
	services.EnableResponseLogging()
	golib.ConfigureOpenFilesLimit()

	redisClient, err := services.ConnectRedis(*redisEndpoint)
	if err != nil {
		log.Fatalln(err)
	}

	if err := services.RegisterLockScripts(redisClient); err != nil {
		log.Fatalln("Failed to register redis scripts", err)
	}

	catalog := &Catalog{
		redis:          redisClient,
		redisLockValue: services.EndpointLockValue(*addr),
	}
	if err := fillDefaultCatalog(catalog); err != nil {
		log.Fatalln("Error filling default catalog:", err)
	}
	go catalog.RefillItems(refill_timeout, map[string]uint64{
		"DVD":       500,
		"Toaster":   100,
		"Laptop":    50,
		"TV":        10,
		"Spaceship": 1,
	})

	mux := mux.NewRouter()
	mux.HandleFunc("/items", catalog.show_items).Methods("GET")
	mux.HandleFunc("/item/{name}", catalog.show_item).Methods("GET")
	mux.HandleFunc("/item/{name}/ship", catalog.ship_item).Methods("POST").MatcherFunc(services.MatchFormKeys("user", "qty", "ts"))
	mux.HandleFunc("/shipment/{id}", catalog.show_shipment).Methods("GET")
	mux.HandleFunc("/shipment/{id}/commit", catalog.commit_shipment).Methods("POST")
	mux.HandleFunc("/shipment/{id}/cancel", catalog.cancel_shipment).Methods("POST")
	mux.HandleFunc("/shipment/{id}/deliver", catalog.deliver_shipment).Methods("POST")
	services.L.Warnf("Running on " + *addr)
	if err := http.ListenAndServe(*addr, mux); err != nil {
		log.Fatal(err)
	}
}
func main() {
	num_users := flag.Uint("users", 5, "Number of simulated people")
	orders_per_user := flag.Uint("orders", 5, "Maximum umber of simultaneous orders per person. 0 for no limitation.")
	bank := flag.String("bank", "localhost:9001", "Bank endpoint")
	timeout := flag.Duration("timeout", 0, "Timeout for automatically stopping load generation")
	dynamicUsers := flag.Bool("dynamic", false, "Enable changing # of active users with arrow keys. CTRL-C breaks console")
	var shops golib.StringSlice
	flag.Var(&shops, "shop", "Shop endpoint(s)")
	flag.Parse()
	if len(shops) == 0 {
		log.Fatalln("Specify at least one -shop")
	}
	golib.ConfigureOpenFilesLimit()
	pool = NewPool(*bank, shops)
	pool.OrdersPerPerson = *orders_per_user
	pool.Start(int(*num_users))

	if *dynamicUsers {
		fixKeyboard = true
		go readKeyboard(func(b byte) {
			switch b {
			case 65: // Up
				pool.StartOne()
			case 66: // Down
				pool.PauseOne()
			case 67: // Right
				pool.Start(10)
			case 68: // Left
				pool.Pause(10)
			case 10: // Enter
				terminate()
			}
		})
	}
	onInterrupt(terminate)
	if *timeout > 0 {
		services.L.Warnf("Terminating automatically after %v", timeout)
		time.AfterFunc(*timeout,
			func() {
				services.L.Warnf("Timer of %v expired. Terminating...", timeout)
				terminate()
			})
	}
	pool.Wait()
	pool.PrintStats()
}
func main() {
	addr := flag.String("listen", "0.0.0.0:9004", "Endpoint address")
	redisEndpoint := flag.String("redis", "127.0.0.1:6379", "Redis endpoint")
	paymentEndpoint := flag.String("payment", "localhost:9002", "Endpoint for payment service")
	catalogEndpoint := flag.String("catalog", "localhost:9003", "Endpoint for catalog service")
	services.ParseBalanceEndpointsFlags()
	flag.Parse()
	services.ParseLoadBalanceConfig()
	services.EnableResponseLogging()
	golib.ConfigureOpenFilesLimit()

	redisClient, err := services.ConnectRedis(*redisEndpoint)
	if err != nil {
		log.Fatalln(err)
	}

	if err := services.RegisterLockScripts(redisClient); err != nil {
		log.Fatalln("Failed to register redis scripts", err)
	}

	shop := &Shop{
		redis:           redisClient,
		redisLockValue:  services.EndpointLockValue(*addr),
		catalogEndpoint: *catalogEndpoint,
		paymentEndpoint: *paymentEndpoint,
	}
	launchOrderProcessing(shop)

	mux := mux.NewRouter()
	mux.HandleFunc("/shop", shop.show_items).Methods("GET")
	mux.HandleFunc("/order", shop.order_item).Methods("POST").MatcherFunc(services.MatchFormKeys("user", "item", "qty"))
	mux.HandleFunc("/order/{order}", shop.get_order).Methods("GET")
	mux.HandleFunc("/orders/{user}", shop.show_orders).Methods("GET")

	services.L.Warnf("Running on " + *addr)
	if err := http.ListenAndServe(*addr, mux); err != nil {
		log.Fatal(err)
	}
}
func main() {
	execFolder, err := osext.ExecutableFolder()
	check(err)
	configFile := flag.String("conf", execFolder+"/isolator.ini", "Config containing isolated external services")
	statsAddr := flag.String("stats", ":7777", "Address to serve statistics (HTTP+JSON on "+stats_path+" and "+runtime_path+")")
	dialTimeout := flag.Duration("timeout", 5*time.Second, "Timeout for outgoing TCP connections")
	flag.Parse()
	golib.ConfigureOpenFilesLimit()

	confIni, err := ini.Load(*configFile)
	check(err)

	p := proxy.NewIsolationProxy(
		loadServiceRegistry(confIni),
		*dialTimeout,
	)
	services.EnableResponseLogging()
	p.ServeStats(stats_path)
	proxy.ServeRuntimeStats(runtime_path)
	handleServices(confIni, p)
	check(http.ListenAndServe(*statsAddr, nil))
}
func main() {
	addr := flag.String("listen", "0.0.0.0:9002", "Endpoint address")
	redisEndpoint := flag.String("redis", "127.0.0.1:6379", "Redis endpoint")
	bankEndpoint := flag.String("bank", "localhost:9001", "Endpoint for bank service")
	services.ParseBalanceEndpointsFlags()
	flag.Parse()
	services.ParseLoadBalanceConfig()
	services.EnableResponseLogging()
	golib.ConfigureOpenFilesLimit()

	bank := bankApi.NewHttpBank(*bankEndpoint)
	redisClient, err := services.ConnectRedis(*redisEndpoint)
	if err != nil {
		log.Fatalln(err)
	}

	if err := services.RegisterLockScripts(redisClient); err != nil {
		log.Fatalln("Failed to register redis scripts", err)
	}

	payments := &Payments{
		bank:           bank,
		redis:          redisClient,
		accountName:    "store",
		redisLockValue: services.EndpointLockValue(*addr),
	}
	mux := mux.NewRouter()
	mux.HandleFunc("/payment", payments.new_payment).Methods("POST").MatcherFunc(services.MatchFormKeys("user", "value", "ts"))
	mux.HandleFunc("/payment/{id}", payments.show_payment).Methods("GET")
	mux.HandleFunc("/payment/{id}/commit", payments.commit_payment).Methods("POST")
	mux.HandleFunc("/payment/{id}/cancel", payments.cancel_payment).Methods("POST")

	services.L.Warnf("Running on " + *addr)
	if err := http.ListenAndServe(*addr, mux); err != nil {
		log.Fatal(err)
	}
}
func main() {
	golib.ConfiguredOpenFilesLimit = 40000
	addr := flag.String("listen", "0.0.0.0:9001", "Endpoint address")
	flag.Parse()
	services.EnableResponseLogging()
	golib.ConfigureOpenFilesLimit()

	store := NewAccountStore(1000, 200)

	mux := mux.NewRouter()
	mux.HandleFunc("/stats", store.show_stats).Methods("GET")
	mux.HandleFunc("/account/{id}", store.show_account).Methods("GET")
	mux.HandleFunc("/account/{id}/deposit", store.handle_deposit).Methods("POST").MatcherFunc(services.MatchFormKeys("value"))
	mux.HandleFunc("/account/{id}/transfer", store.handle_transfer).Methods("POST").MatcherFunc(services.MatchFormKeys("value", "target"))
	mux.HandleFunc("/transaction/{id}", store.show_transaction).Methods("GET")
	mux.HandleFunc("/transaction/{id}/cancel", store.cancel_transaction).Methods("POST")
	mux.HandleFunc("/transaction/{id}/revert", store.revert_transaction).Methods("POST")
	mux.HandleFunc("/transaction/{id}/commit", store.commit_transaction).Methods("POST")

	services.L.Warnf("Running on " + *addr)
	if err := http.ListenAndServe(*addr, mux); err != nil {
		log.Fatal(err)
	}
}
func main() {
	num_users := flag.Uint64("users", 1000, "Number of users to check")
	verbose := flag.Bool("v", false, "Print processing details")
	bankEndpoint := flag.String("bank", "localhost:9001", "Bank endpoint")
	var shopEndpoint string
	flag.StringVar(&shopEndpoint, "shop", "localhost:9004", "Shop endpoint")
	flag.Parse()
	golib.ConfigureOpenFilesLimit()
	bank := bankApi.NewHttpBank(*bankEndpoint)
	inconsistent := false

	allItems, err := shopApi.AllItems(shopEndpoint)
	itemMap := make(map[string]*shopApi.Item)
	var totalEarned float64
	var totalShipped uint64
	for _, item := range allItems {
		itemMap[item.Name] = item
		total := item.Reserved + item.Shipped + item.Stock
		initial := initialItems[item.Name]
		expectedTotal := initial + item.Refills
		if total != expectedTotal {
			fmt.Printf("%v inconsistent: %v + %v + %v = %v, expected %v + %v = %v\n", item.Name, item.Reserved, item.Shipped, item.Stock, total, initial, item.Refills, expectedTotal)
			inconsistent = true
		}
		if item.Reserved != 0 {
			fmt.Printf("%v still has %v reserved items\n", item.Name, item.Reserved)
			inconsistent = true
		}
		totalShipped += item.Shipped
		totalEarned += float64(item.Shipped) * item.Cost
	}
	if !inconsistent {
		fmt.Println("All items are consistent!")
	}

	var cancelledOrders uint64
	var processedOrders uint64
	var totalEarnedOrders float64
	var totalShippedOrders uint64
	var totalProcessingOrders uint64
	for i := uint64(0); i < *num_users; i++ {
		user := fmt.Sprintf("User%v", i)
		orders, err := shopApi.AllOrders(shopEndpoint, user)
		check(err)

		if *verbose {
			fmt.Printf("Checking %v orders of user %v (%v of %v users)\n", len(orders), user, i, *num_users)
		}

		for _, order := range orders {
			if strings.HasPrefix(order.Status, "Order processed successfully") {
				item := itemMap[order.Item]
				totalShippedOrders += order.Quantity
				totalEarnedOrders += float64(order.Quantity) * item.Cost
				processedOrders++
			} else if strings.HasPrefix(order.Status, "Cancelling because of:") {
				cancelledOrders++
			} else if order.Status == shopApi.OrderStatusProcessing {
				totalProcessingOrders++
			} else {
				fmt.Println("Unknown order status:", order.Status)
				inconsistent = true
				break
			}
		}
	}
	fmt.Println("Orders processed:", processedOrders, "orders cancelled:", cancelledOrders)
	if totalProcessingOrders > 0 {
		fmt.Printf("UNFINISHED: There are still %v orders to process\n", totalProcessingOrders)
		inconsistent = true
	}
	if totalShipped != totalShippedOrders {
		fmt.Printf("Inconsistent: shipped %v, shipped orders %v\n", totalShipped, totalShippedOrders)
		inconsistent = true
	}

	balance, err := bank.Balance("store")
	check(err)

	balance = round(balance)
	totalEarnedOrders = round(totalEarnedOrders)
	totalEarned = round(totalEarned)

	if balance != totalEarned {
		fmt.Printf("Inconsistent earnings bank vs. items. Expected %v, have %v\n", totalEarned, balance)
		inconsistent = true
		if balance > totalEarned {
			fmt.Println(balance-totalEarned, "too much")
		} else {
			fmt.Println("Missing", totalEarned-balance)
		}
	}
	if balance != totalEarnedOrders {
		fmt.Printf("Inconsistent earnings bank vs. orders. Expected %v, have %v\n", totalEarnedOrders, balance)
		inconsistent = true
		if balance > totalEarnedOrders {
			fmt.Println(balance-totalEarnedOrders, "too much")
		} else {
			fmt.Println("Missing", totalEarnedOrders-balance)
		}
	}
	fmt.Printf("Total shipped items %v, total earnings %v\n", totalShipped, totalEarned)

	if inconsistent {
		fmt.Printf("MAYBE THERE WERE MORE THAN %v USERS?\n", *num_users)
		os.Exit(1)
	} else {
		os.Exit(0)
	}
}