hunk.code_window: 	app.Srv.Store = app.newStore()
   	if err := app.ensureAsymmetricSigningKey(); err != nil {
   		return nil, errors.Wrapf(err, "unable to ensure asymmetric signing key")
   	}
   	app.initJobs()
   	app.AddLicenseListener(func() {
   		app.initJobs()
   	})
  
hunk.labels: keep keep keep keep add keep keep keep keep keep
hunk.after_edit: 	app.EnsureDiagnosticId()
   	app.regenerateClientConfig()
  
hunk.file_path: app/app.go
hunk.type: add
file: package dns
  
  import (
  	"bytes"
  	"errors"
  	"fmt"
  	"strconv"
  	"strings"
  )
  
  // Parse the $GENERATE statement as used in BIND9 zones.
  // See http://www.zytrax.com/books/dns/ch8/generate.html for instance.
  // We are called after '$GENERATE '. After which we expect:
  // * the range (12-24/2)
  // * lhs (ownername)
  // * [[ttl][class]]
  // * type
  // * rhs (rdata)
  // But we are lazy here, only the range is parsed *all* occurrences
  // of $ after that are interpreted.
  // Any error are returned as a string value, the empty string signals
  // "no error".
  func generate(l lex, c chan lex, t chan *Token, o string) string {
  	step := 1
  	if i := strings.IndexAny(l.token, "/"); i != -1 {
  		if i+1 == len(l.token) {
  			return "bad step in $GENERATE range"
  		}
  		if s, err := strconv.Atoi(l.token[i+1:]); err == nil {
  			if s < 0 {
  				return "bad step in $GENERATE range"
  			}
  			step = s
  		} else {
  			return "bad step in $GENERATE range"
  		}
  		l.token = l.token[:i]
  	}
  	sx := strings.SplitN(l.token, "-", 2)
  	if len(sx) != 2 {
  		return "bad start-stop in $GENERATE range"
  	}
  	start, err := strconv.Atoi(sx[0])
  	if err != nil {
  		return "bad start in $GENERATE range"
  	}
  	end, err := strconv.Atoi(sx[1])
  	if err != nil {
  		return "bad stop in $GENERATE range"
  	}
  	if end < 0 || start < 0 || end < start {
  		return "bad range in $GENERATE range"
  	}
  
  	<-c // _BLANK
  	// Create a complete new string, which we then parse again.
  	s := ""
  BuildRR:
  	l = <-c
  	if l.value != zNewline && l.value != zEOF {
  		s += l.token
  		goto BuildRR
  	}
  	for i := start; i <= end; i += step {
  		var (
  			escape bool
  			dom    bytes.Buffer
  			mod    string
  			err    error
  			offset int
  		)
  
  		for j := 0; j < len(s); j++ { // No 'range' because we need to jump around
  			switch s[j] {
  			case '\\':
  				if escape {
  					dom.WriteByte('\\')
  					escape = false
  					continue
  				}
  				escape = true
  			case '$':
  				mod = "%d"
  				offset = 0
  				if escape {
  					dom.WriteByte('$')
  					escape = false
  					continue
  				}
  				escape = false
  				if j+1 >= len(s) { // End of the string
  					dom.WriteString(fmt.Sprintf(mod, i+offset))
  					continue
  				} else {
  					if s[j+1] == '$' {
  						dom.WriteByte('$')
  						j++
  						continue
  					}
  				}
  				// Search for { and }
  				if s[j+1] == '{' { // Modifier block
  					sep := strings.Index(s[j+2:], "}")
  					if sep == -1 {
  						return "bad modifier in $GENERATE"
  					}
  					mod, offset, err = modToPrintf(s[j+2 : j+2+sep])
  					if err != nil {
  						return err.Error()
  					}
  					j += 2 + sep // Jump to it
  				}
  				dom.WriteString(fmt.Sprintf(mod, i+offset))
  			default:
  				if escape { // Pretty useless here
  					escape = false
  					continue
  				}
  				dom.WriteByte(s[j])
  			}
  		}
  		// Re-parse the RR and send it on the current channel t
  		rx, err := NewRR("$ORIGIN " + o + "\n" + dom.String())
  		if err != nil {
  			return err.Error()
  		}
  		t <- &Token{RR: rx}
  		// Its more efficient to first built the rrlist and then parse it in
  		// one go! But is this a problem?
  	}
  	return ""
  }
  
  // Convert a $GENERATE modifier 0,0,d to something Printf can deal with.
  func modToPrintf(s string) (string, int, error) {
  	xs := strings.SplitN(s, ",", 3)
  	if len(xs) != 3 {
  		return "", 0, errors.New("bad modifier in $GENERATE")
  	}
  	// xs[0] is offset, xs[1] is width, xs[2] is base
  	if xs[2] != "o" && xs[2] != "d" && xs[2] != "x" && xs[2] != "X" {
  		return "", 0, errors.New("bad base in $GENERATE")
  	}
  	offset, err := strconv.Atoi(xs[0])
  	if err != nil || offset > 255 {
  		return "", 0, errors.New("bad offset in $GENERATE")
  	}
  	width, err := strconv.Atoi(xs[1])
  	if err != nil || width > 255 {
  		return "", offset, errors.New("bad width in $GENERATE")
  	}
  	switch {
  	case width < 0:
  		return "", offset, errors.New("bad width in $GENERATE")
  	case width == 0:
  		return "%" + xs[1] + xs[2], offset, nil
  	}
  	return "%0" + xs[1] + xs[2], offset, nil
  }
  