| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -119,6 +119,7 @@ func checkFiles() {
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							fmt.Printf("%s\n", err) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							os.Exit(1) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						// TODO check other needed files
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func clearScreen() { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -203,30 +204,14 @@ func printUserScreen(redisClient *redis.Client, username string) string {
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								clearScreen() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								printProgressScreen(redisClient) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							case "p": | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								// TODO save to inprogress
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								// SADD user to an inprogress redis set
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								// SET inprogress:user and expire it to 10 seconds
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//   start goroutine that keeps upping expire time every 8 or so seconds
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//   when goroutine exists, the key will be allowed to expire
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								// have a janitor that watches inprogress set
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//   janitor looks at every user in 'inprogress' and checks if the key remains
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//   if the key is gone, janitor kills the user from redis set
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								wg.Add(1) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								go runGame(username) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								watcher := startWatcher(username, redisClient) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								currentTime := time.Now().UTC() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								fulltime := currentTime.Format("2006-01-02.03:04:05") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								go runGame(username, fulltime) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								watcher := startWatcher(username, fulltime, redisClient) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								wg.Wait() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								fmt.Println("CLOSING") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								close(watcher) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//nhCommand := fmt.Sprintf("nethack -d %s -u %s\n", config.NethackLauncher.HackDir, username)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//ttyrecPath := fmt.Sprintf("%s/user/%s/ttyrec/yeet.ttyrec", config.NethackLauncher.HackDir, username)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//exec.Command("stty", "-F", "/dev/tty", "echo", "-cbreak").Run()
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//clearScreen()
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//nh := exec.Command("ttyrec", ttyrecPath, "-e", nhCommand)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//nh.Stdout = os.Stdout
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//nh.Stdin = os.Stdin
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//nh.Stderr = os.Stderr
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//nh.Run()
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//exec.Command("exit").Run()
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								printUserScreen(redisClient, username) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							case "q": | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								exec.Command("stty", "-F", "/dev/tty", "echo", "-cbreak").Run() | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -354,7 +339,6 @@ func printRegisterScreen(redisClient *redis.Client) {
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								// TODO create config file
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								// HackDir/user/username/<config>
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								// HackDir/user/username/ttyrec/
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								// create user directories
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								userPath := fmt.Sprintf("%s/user/%s/ttyrec/", config.NethackLauncher.HackDir, username) | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -370,64 +354,37 @@ func printRegisterScreen(redisClient *redis.Client) {
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func printProgressScreen(redisClient *redis.Client) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						// TODO check if user is logged in and take them back to login screen after blank entry
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						// print header
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						fmt.Printf(" %s\n", config.NethackLauncher.ServerDisplay) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						println("") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						// check directory for live players
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						isEmpty, err := checkDir(config.NethackLauncher.InProgressDir) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						isNotEmpty, err := redisClient.Exists("inprogress").Result() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							panic(err) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if isEmpty { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							println(" No live players currently (blank entry returns)") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if isNotEmpty { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							println(" Choose a player to spectate ('enter' without selection returns)") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							println(" No live players currently (blank entry returns)") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						println("") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						// populate inProg map
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						// create map for storing in progress data
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						inProg := make(map[int]string) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						inProgTimer := 1 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						inprogress, err := redisClient.SMembers("inprogress").Result() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							panic(err) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						for _, i := range inprogress { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							// loop through users
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							fmt.Printf(" %d) %s\n", inProgTimer, i) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						progFiles, _ := ioutil.ReadDir(config.NethackLauncher.InProgressDir) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						for _, f := range progFiles { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							// grab username and path into user[]
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							user := strings.Split(f.Name(), ":") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							// get resolution lines from file
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							res0 := "" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							res1 := "" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							filePath := fmt.Sprintf("%s/%s", config.NethackLauncher.InProgressDir, f.Name()) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							fileIO, err := os.OpenFile(filePath, os.O_RDWR, 0600) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								panic(err) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							defer fileIO.Close() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							rawBytes, err := ioutil.ReadAll(fileIO) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							if err != nil { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								panic(err) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							lines := strings.Split(string(rawBytes), "\n") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							for i, line := range lines { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								if i == 1 { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									res1 = line | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								if i == 2 { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									res0 = line | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							// print user line
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							fmt.Printf(" %d) %s\t%sx%s\t%s\n", inProgTimer, user[0], res0, res1, user[1]) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							// add user line to map
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							inProg[inProgTimer] = f.Name() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							// add user to line map
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							inProg[inProgTimer] = i | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							inProgTimer++ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						println("") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						fmt.Printf(">> ") | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						// start user input
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -455,7 +412,8 @@ func printProgressScreen(redisClient *redis.Client) {
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								fmt.Printf("going to spectate '%s'\n", user[0]) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								// set ttyrec path
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								ttyrecPath := fmt.Sprintf("%s/%s/%s/ttyrec/%s:%s:%s.ttyrec", config.NethackLauncher.UserDir, user[0][0:1], user[0], user[1], user[2], user[3]) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								ttyName, _ := redisClient.Get(fmt.Sprintf("inprogress:%s", user[0])).Result() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								ttyrecPath := fmt.Sprintf("%s/user/%s/ttyrec/%s.ttyrec", config.NethackLauncher.HackDir, user[0], ttyName) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								// restart display
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								exec.Command("stty", "-F", "/dev/tty", "echo", "-cbreak").Run() | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -466,14 +424,16 @@ func printProgressScreen(redisClient *redis.Client) {
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								nh.Stderr = os.Stderr | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								nh.Run() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								// TODO add username to this
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								// TODO fix bug where user has to <ctrl-c> when game exists
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								//printUserScreen(redisClient, username)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								printWelcomeScreen(redisClient) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func runGame(username string) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func runGame(username, timestamp string) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						nhCommand := fmt.Sprintf("nethack -d %s -u %s\n", config.NethackLauncher.HackDir, username) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						ttyrecPath := fmt.Sprintf("%s/user/%s/ttyrec/yeet.ttyrec", config.NethackLauncher.HackDir, username) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						ttyrecPath := fmt.Sprintf("%s/user/%s/ttyrec/%s.ttyrec", config.NethackLauncher.HackDir, username, timestamp) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						exec.Command("stty", "-F", "/dev/tty", "echo", "-cbreak").Run() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						clearScreen() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						nh := exec.Command("ttyrec", ttyrecPath, "-e", nhCommand) | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -485,10 +445,10 @@ func runGame(username string) {
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						wg.Done() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func startWatcher(username string, redisClient *redis.Client) chan struct{} { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					func startWatcher(username, timestamp string, redisClient *redis.Client) chan struct{} { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						// create initial keys
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						redisClient.SAdd("inprogress", username) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						redisClient.Set(fmt.Sprintf("inprogress:%s", username), "", 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						redisClient.Set(fmt.Sprintf("inprogress:%s", username), timestamp, 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						ch := make(chan struct{}) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						// enter inital inprogress yet
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				 | 
				
					
 
					 |