Break check_for_misspaced_punctuation() out
authorali <ali@juiblex.co.uk>
Sun May 26 17:23:48 2013 +0100 (2013-05-26)
changeset 568ade5460e220
parent 55 6b786cc05b3c
child 57 1e89f47e56df
Break check_for_misspaced_punctuation() out
bookloupe/bookloupe.c
     1.1 --- a/bookloupe/bookloupe.c	Sun May 26 16:54:06 2013 +0100
     1.2 +++ b/bookloupe/bookloupe.c	Sun May 26 17:23:48 2013 +0100
     1.3 @@ -1781,6 +1781,252 @@
     1.4      }
     1.5  }
     1.6  
     1.7 +struct parities {
     1.8 +    int dquote,squote;
     1.9 +};
    1.10 +
    1.11 +/*
    1.12 + * check_for_misspaced_punctuation:
    1.13 + *
    1.14 + * Look for added or missing spaces around punctuation and quotes.
    1.15 + * If there is a punctuation character like ! with no space on
    1.16 + * either side, suspect a missing!space. If there are spaces on
    1.17 + * both sides , assume a typo. If we see a double quote with no
    1.18 + * space or punctuation on either side of it, assume unspaced
    1.19 + * quotes "like"this.
    1.20 + */
    1.21 +void check_for_misspaced_punctuation(const char *aline,
    1.22 +  struct parities *parities,int isemptyline)
    1.23 +{
    1.24 +    int i,llen,isacro,isellipsis;
    1.25 +    const char *s;
    1.26 +    llen=strlen(aline);
    1.27 +    for (i=1;i<llen;i++)
    1.28 +    {
    1.29 +	/* For each character in the line after the first. */
    1.30 +	if (strchr(".?!,;:_",aline[i]))  /* if it's punctuation */
    1.31 +	{
    1.32 +	    /* we need to suppress warnings for acronyms like M.D. */
    1.33 +	    isacro=0;
    1.34 +	    /* we need to suppress warnings for ellipsis . . . */
    1.35 +	    isellipsis=0;
    1.36 +	    /* if there are letters on both sides of it or ... */
    1.37 +	    if (gcisalpha(aline[i-1]) && gcisalpha(aline[i+1]) ||
    1.38 +	       gcisalpha(aline[i+1]) && strchr("?!,;:",aline[i]))
    1.39 +	    {
    1.40 +		/* ...if it's strict punctuation followed by an alpha */
    1.41 +		if (aline[i]=='.')
    1.42 +		{
    1.43 +		    if (i>2 && aline[i-2]=='.')
    1.44 +			isacro=1;
    1.45 +		    if (i+2<llen && aline[i+2]=='.')
    1.46 +			isacro=1;
    1.47 +		}
    1.48 +		if (!isacro)
    1.49 +		{
    1.50 +		    if (pswit[ECHO_SWITCH])
    1.51 +			printf("\n%s\n",aline);
    1.52 +		    if (!pswit[OVERVIEW_SWITCH])
    1.53 +			printf("    Line %ld column %d - Missing space?\n",
    1.54 +			  linecnt,i+1);
    1.55 +		    else
    1.56 +			cnt_punct++;
    1.57 +		}
    1.58 +	    }
    1.59 +	    if (aline[i-1]==CHAR_SPACE &&
    1.60 +	      (aline[i+1]==CHAR_SPACE || aline[i+1]==0))
    1.61 +	    {
    1.62 +		/*
    1.63 +		 * If there are spaces on both sides,
    1.64 +		 * or space before and end of line.
    1.65 +		 */
    1.66 +		if (aline[i]=='.')
    1.67 +		{
    1.68 +		    if (i>2 && aline[i-2]=='.')
    1.69 +			isellipsis=1;
    1.70 +		    if (i+2<llen && aline[i+2]=='.')
    1.71 +			isellipsis=1;
    1.72 +		}
    1.73 +		if (!isemptyline && !isellipsis)
    1.74 +		{
    1.75 +		    if (pswit[ECHO_SWITCH])
    1.76 +			printf("\n%s\n",aline);
    1.77 +		    if (!pswit[OVERVIEW_SWITCH])
    1.78 +			printf("    Line %ld column %d - "
    1.79 +			  "Spaced punctuation?\n",linecnt,i+1);
    1.80 +		    else
    1.81 +			cnt_punct++;
    1.82 +		}
    1.83 +	    }
    1.84 +	}
    1.85 +    }
    1.86 +    /* Split out the characters that CANNOT be preceded by space. */
    1.87 +    llen=strlen(aline);
    1.88 +    for (i=1;i<llen;i++)
    1.89 +    {
    1.90 +	/* for each character in the line after the first */
    1.91 +	if (strchr("?!,;:",aline[i]))
    1.92 +	{
    1.93 +	    /* if it's punctuation that _cannot_ have a space before it */
    1.94 +	    if (aline[i-1]==CHAR_SPACE && !isemptyline &&
    1.95 +	      aline[i+1]!=CHAR_SPACE)
    1.96 +	    {
    1.97 +		/*
    1.98 +		 * If aline[i+1) DOES == space,
    1.99 +		 * it was already reported just above.
   1.100 +		 */
   1.101 +		if (pswit[ECHO_SWITCH])
   1.102 +		    printf("\n%s\n",aline);
   1.103 +		if (!pswit[OVERVIEW_SWITCH])
   1.104 +		    printf("    Line %ld column %d - Spaced punctuation?\n",
   1.105 +		      linecnt,i+1);
   1.106 +		else
   1.107 +		    cnt_punct++;
   1.108 +	    }
   1.109 +	}
   1.110 +    }
   1.111 +    /*
   1.112 +     * Special case " .X" where X is any alpha.
   1.113 +     * This plugs a hole in the acronym code above.
   1.114 +     * Inelegant, but maintainable.
   1.115 +     */
   1.116 +    llen=strlen(aline);
   1.117 +    for (i=1;i<llen;i++)
   1.118 +    {
   1.119 +	/* for each character in the line after the first */
   1.120 +	if (aline[i]=='.')
   1.121 +	{
   1.122 +	    /* if it's a period */
   1.123 +	    if (aline[i-1]==CHAR_SPACE && gcisalpha(aline[i+1]))
   1.124 +	    {
   1.125 +		/*
   1.126 +		 * If the period follows a space and
   1.127 +		 * is followed by a letter.
   1.128 +		 */
   1.129 +		if (pswit[ECHO_SWITCH])
   1.130 +		    printf("\n%s\n",aline);
   1.131 +		if (!pswit[OVERVIEW_SWITCH])
   1.132 +		    printf("    Line %ld column %d - Spaced punctuation?\n",
   1.133 +		      linecnt,i+1);
   1.134 +		else
   1.135 +		    cnt_punct++;
   1.136 +	    }
   1.137 +	}
   1.138 +    }
   1.139 +    for (i=1;i<llen;i++)
   1.140 +    {
   1.141 +	/* for each character in the line after the first */
   1.142 +	if (aline[i]==CHAR_DQUOTE)
   1.143 +	{
   1.144 +	    if (!strchr(" _-.'`,;:!/([{?}])",aline[i-1]) &&
   1.145 +	      !strchr(" _-.'`,;:!/([{?}])",aline[i+1]) && aline[i+1] ||
   1.146 +	      !strchr(" _-([{'`",aline[i-1]) && gcisalpha(aline[i+1]))
   1.147 +	    {
   1.148 +		if (pswit[ECHO_SWITCH])
   1.149 +		    printf("\n%s\n",aline);
   1.150 +		if (!pswit[OVERVIEW_SWITCH])
   1.151 +		    printf("    Line %ld column %d - Unspaced quotes?\n",
   1.152 +		      linecnt,i+1);
   1.153 +		else
   1.154 +		    cnt_punct++;
   1.155 +	    }
   1.156 +	}
   1.157 +    }
   1.158 +    /* Check parity of quotes. */
   1.159 +    for (s=aline;*s;s++)
   1.160 +    {
   1.161 +	if (*s==CHAR_DQUOTE)
   1.162 +	{
   1.163 +	    parities->dquote=!parities->dquote;
   1.164 +	    if (!parities->dquote)
   1.165 +	    {
   1.166 +		/* parity even */
   1.167 +		if (!strchr("_-.'`/,;:!?)]} ",s[1]))
   1.168 +		{
   1.169 +		    if (pswit[ECHO_SWITCH])
   1.170 +			printf("\n%s\n",aline);
   1.171 +		    if (!pswit[OVERVIEW_SWITCH])
   1.172 +			printf("    Line %ld column %d - "
   1.173 +			  "Wrongspaced quotes?\n",linecnt,(int)(s-aline)+1);
   1.174 +		    else
   1.175 +			cnt_punct++;
   1.176 +		}
   1.177 +	    }
   1.178 +	    else
   1.179 +	    {
   1.180 +		/* parity odd */
   1.181 +		if (!gcisalpha(s[1]) && !isdigit(s[1]) &&
   1.182 +		  !strchr("_-/.'`([{$",s[1]) || !s[1])
   1.183 +		{
   1.184 +		    if (pswit[ECHO_SWITCH])
   1.185 +			printf("\n%s\n",aline);
   1.186 +		    if (!pswit[OVERVIEW_SWITCH])
   1.187 +			printf("    Line %ld column %d - "
   1.188 +			  "Wrongspaced quotes?\n",linecnt,(int)(s-aline)+1);
   1.189 +		    else
   1.190 +			cnt_punct++;
   1.191 +		}
   1.192 +	    }
   1.193 +	}
   1.194 +    }
   1.195 +    if (*aline==CHAR_DQUOTE)
   1.196 +    {
   1.197 +	if (strchr(",;:!?)]} ",aline[1]))
   1.198 +	{
   1.199 +	    if (pswit[ECHO_SWITCH])
   1.200 +		printf("\n%s\n",aline);
   1.201 +	    if (!pswit[OVERVIEW_SWITCH])
   1.202 +		printf("    Line %ld column 1 - Wrongspaced quotes?\n",
   1.203 +		  linecnt);
   1.204 +	    else
   1.205 +		cnt_punct++;
   1.206 +	}
   1.207 +    }
   1.208 +    if (pswit[SQUOTE_SWITCH])
   1.209 +    {
   1.210 +	for (s=aline;*s;s++)
   1.211 +	{
   1.212 +	    if ((*s==CHAR_SQUOTE || *s==CHAR_OPEN_SQUOTE) &&
   1.213 +	      (s==aline || s>aline && !gcisalpha(s[-1]) ||
   1.214 +	      !gcisalpha(s[1])))
   1.215 +	    {
   1.216 +		parities->squote=!parities->squote;
   1.217 +		if (!parities->squote)
   1.218 +		{
   1.219 +		    /* parity even */
   1.220 +		    if (!strchr("_-.'`/\",;:!?)]} ",s[1]))
   1.221 +		    {
   1.222 +			if (pswit[ECHO_SWITCH])
   1.223 +			    printf("\n%s\n",aline);
   1.224 +			if (!pswit[OVERVIEW_SWITCH])
   1.225 +			    printf("    Line %ld column %d - "
   1.226 +			      "Wrongspaced singlequotes?\n",
   1.227 +			      linecnt,(int)(s-aline)+1);
   1.228 +			else
   1.229 +			    cnt_punct++;
   1.230 +		    }
   1.231 +		}
   1.232 +		else
   1.233 +		{
   1.234 +		    /* parity odd */
   1.235 +		    if (!gcisalpha(s[1]) && !isdigit(s[1]) &&
   1.236 +		      !strchr("_-/\".'`",s[1]) || !s[1])
   1.237 +		    {
   1.238 +			if (pswit[ECHO_SWITCH])
   1.239 +			    printf("\n%s\n",aline);
   1.240 +			if (!pswit[OVERVIEW_SWITCH])
   1.241 +			    printf("    Line %ld column %d - "
   1.242 +			      "Wrongspaced singlequotes?\n",
   1.243 +			      linecnt,(int)(s-aline)+1);
   1.244 +			else
   1.245 +			    cnt_punct++;
   1.246 +		    }
   1.247 +		}
   1.248 +	    }
   1.249 +	}
   1.250 +    }
   1.251 +}
   1.252 +
   1.253  /*
   1.254   * procfile:
   1.255   *
   1.256 @@ -1795,10 +2041,10 @@
   1.257      struct warnings *warnings;
   1.258      struct counters counters={0};
   1.259      struct line_properties last={0};
   1.260 +    struct parities parities={0};
   1.261      int isemptyline;
   1.262      long squot,start_para_line;
   1.263      signed int i,llen,isacro,isellipsis;
   1.264 -    signed int dquotepar,squotepar;
   1.265      signed int isnewpara;
   1.266      char dquote_err[80],squote_err[80],rbrack_err[80],sbrack_err[80],
   1.267        cbrack_err[80],unders_err[80];
   1.268 @@ -1810,7 +2056,6 @@
   1.269      squot=0;
   1.270      i=llen=isacro=isellipsis=0;
   1.271      isnewpara=enddash=0;
   1.272 -    dquotepar=squotepar=0;
   1.273      infile=fopen(filename,"rb");
   1.274      if (!infile)
   1.275      {
   1.276 @@ -1946,7 +2191,7 @@
   1.277  	    /* Capture its first line in case we want to report it later. */
   1.278              strncpy(parastart,aline,80);
   1.279              parastart[79]=0;
   1.280 -            dquotepar=squotepar=0; /* restart the quote count */
   1.281 +	    memset(&parities,0,sizeof(parities));  /* restart the quote count */
   1.282              s=aline;
   1.283              while (!gcisalpha(*s) && !gcisdigit(*s) && *s)
   1.284  		s++;
   1.285 @@ -2022,237 +2267,7 @@
   1.286  	check_for_extra_period(aline,warnings);
   1.287  	check_for_following_punctuation(aline);
   1.288  	check_for_typos(aline,warnings);
   1.289 -	/*
   1.290 -         * Look for added or missing spaces around punctuation and quotes.
   1.291 -         * If there is a punctuation character like ! with no space on
   1.292 -         * either side, suspect a missing!space. If there are spaces on
   1.293 -         * both sides , assume a typo. If we see a double quote with no
   1.294 -         * space or punctuation on either side of it, assume unspaced
   1.295 -         * quotes "like"this.
   1.296 -	 */
   1.297 -        llen=strlen(aline);
   1.298 -        for (i=1;i<llen;i++)
   1.299 -	{
   1.300 -	    /* For each character in the line after the first. */
   1.301 -            if (strchr(".?!,;:_",aline[i]))  /* if it's punctuation */
   1.302 -	    {
   1.303 -		/* we need to suppress warnings for acronyms like M.D. */
   1.304 -                isacro=0;
   1.305 -		/* we need to suppress warnings for ellipsis . . . */
   1.306 -                isellipsis=0;
   1.307 -		/* if there are letters on both sides of it or ... */
   1.308 -                if (gcisalpha(aline[i-1]) && gcisalpha(aline[i+1]) ||
   1.309 -                   gcisalpha(aline[i+1]) && strchr("?!,;:",aline[i]))
   1.310 -		{
   1.311 -		    /* ...if it's strict punctuation followed by an alpha */
   1.312 -                    if (aline[i]=='.')
   1.313 -		    {
   1.314 -                        if (i>2 && aline[i-2]=='.')
   1.315 -			    isacro=1;
   1.316 -                        if (i+2<llen && aline[i+2]=='.')
   1.317 -			    isacro=1;
   1.318 -		    }
   1.319 -                    if (!isacro)
   1.320 -		    {
   1.321 -                        if (pswit[ECHO_SWITCH])
   1.322 -			    printf("\n%s\n",aline);
   1.323 -                        if (!pswit[OVERVIEW_SWITCH])
   1.324 -                            printf("    Line %ld column %d - Missing space?\n",
   1.325 -			      linecnt,i+1);
   1.326 -                        else
   1.327 -                            cnt_punct++;
   1.328 -		    }
   1.329 -		}
   1.330 -                if (aline[i-1]==CHAR_SPACE &&
   1.331 -		  (aline[i+1]==CHAR_SPACE || aline[i+1]==0))
   1.332 -		{
   1.333 -		    /*
   1.334 -		     * If there are spaces on both sides,
   1.335 -		     * or space before and end of line.
   1.336 -		     */
   1.337 -                    if (aline[i]=='.')
   1.338 -		    {
   1.339 -                        if (i>2 && aline[i-2]=='.')
   1.340 -			    isellipsis=1;
   1.341 -                        if (i+2<llen && aline[i+2]=='.')
   1.342 -			    isellipsis=1;
   1.343 -		    }
   1.344 -                    if (!isemptyline && !isellipsis)
   1.345 -		    {
   1.346 -                        if (pswit[ECHO_SWITCH])
   1.347 -			    printf("\n%s\n",aline);
   1.348 -                        if (!pswit[OVERVIEW_SWITCH])
   1.349 -                            printf("    Line %ld column %d - "
   1.350 -			      "Spaced punctuation?\n",linecnt,i+1);
   1.351 -                        else
   1.352 -                            cnt_punct++;
   1.353 -		    }
   1.354 -		}
   1.355 -	    }
   1.356 -	}
   1.357 -        /* Split out the characters that CANNOT be preceded by space. */
   1.358 -        llen=strlen(aline);
   1.359 -        for (i=1;i<llen;i++)
   1.360 -	{
   1.361 -	    /* for each character in the line after the first */
   1.362 -            if (strchr("?!,;:",aline[i]))
   1.363 -	    {
   1.364 -		/* if it's punctuation that _cannot_ have a space before it */
   1.365 -                if (aline[i-1]==CHAR_SPACE && !isemptyline &&
   1.366 -		  aline[i+1]!=CHAR_SPACE)
   1.367 -		{
   1.368 -		    /*
   1.369 -		     * If aline[i+1) DOES == space,
   1.370 -		     * it was already reported just above.
   1.371 -		     */
   1.372 -                    if (pswit[ECHO_SWITCH])
   1.373 -			printf("\n%s\n",aline);
   1.374 -                    if (!pswit[OVERVIEW_SWITCH])
   1.375 -                        printf("    Line %ld column %d - Spaced punctuation?\n",
   1.376 -			  linecnt,i+1);
   1.377 -                    else
   1.378 -                        cnt_punct++;
   1.379 -		}
   1.380 -	    }
   1.381 -	}
   1.382 -        /*
   1.383 -	 * Special case " .X" where X is any alpha.
   1.384 -         * This plugs a hole in the acronym code above.
   1.385 -	 * Inelegant, but maintainable.
   1.386 -	 */
   1.387 -        llen=strlen(aline);
   1.388 -        for (i=1;i<llen;i++)
   1.389 -	{
   1.390 -	    /* for each character in the line after the first */
   1.391 -            if (aline[i]=='.')
   1.392 -	    {
   1.393 -		/* if it's a period */
   1.394 -                if (aline[i-1]==CHAR_SPACE && gcisalpha(aline[i+1]))
   1.395 -		{
   1.396 -		    /*
   1.397 -		     * If the period follows a space and
   1.398 -		     * is followed by a letter.
   1.399 -		     */
   1.400 -                    if (pswit[ECHO_SWITCH])
   1.401 -			printf("\n%s\n",aline);
   1.402 -                    if (!pswit[OVERVIEW_SWITCH])
   1.403 -                        printf("    Line %ld column %d - Spaced punctuation?\n",
   1.404 -			  linecnt,i+1);
   1.405 -                    else
   1.406 -                        cnt_punct++;
   1.407 -		}
   1.408 -	    }
   1.409 -	}
   1.410 -        for (i=1;i<llen;i++)
   1.411 -	{
   1.412 -	    /* for each character in the line after the first */
   1.413 -            if (aline[i]==CHAR_DQUOTE)
   1.414 -	    {
   1.415 -                if (!strchr(" _-.'`,;:!/([{?}])",aline[i-1]) &&
   1.416 -		  !strchr(" _-.'`,;:!/([{?}])",aline[i+1]) && aline[i+1] ||
   1.417 -		  !strchr(" _-([{'`",aline[i-1]) && gcisalpha(aline[i+1]))
   1.418 -		{
   1.419 -		    if (pswit[ECHO_SWITCH])
   1.420 -			printf("\n%s\n",aline);
   1.421 -		    if (!pswit[OVERVIEW_SWITCH])
   1.422 -			printf("    Line %ld column %d - Unspaced quotes?\n",
   1.423 -			  linecnt,i+1);
   1.424 -		    else
   1.425 -			cnt_punct++;
   1.426 -		}
   1.427 -	    }
   1.428 -	}
   1.429 -        /* Check parity of quotes. */
   1.430 -        for (s=aline;*s;s++)
   1.431 -	{
   1.432 -            if (*s==CHAR_DQUOTE)
   1.433 -	    {
   1.434 -                if (!(dquotepar=!dquotepar))
   1.435 -		{
   1.436 -		    /* parity even */
   1.437 -                    if (!strchr("_-.'`/,;:!?)]} ",s[1]))
   1.438 -		    {
   1.439 -                        if (pswit[ECHO_SWITCH])
   1.440 -			    printf("\n%s\n",aline);
   1.441 -                        if (!pswit[OVERVIEW_SWITCH])
   1.442 -                            printf("    Line %ld column %d - "
   1.443 -			      "Wrongspaced quotes?\n",linecnt,(int)(s-aline)+1);
   1.444 -                        else
   1.445 -                            cnt_punct++;
   1.446 -		    }
   1.447 -		}
   1.448 -                else
   1.449 -		{
   1.450 -		    /* parity odd */
   1.451 -                    if (!gcisalpha(s[1]) && !isdigit(s[1]) &&
   1.452 -		      !strchr("_-/.'`([{$",s[1]) || !s[1])
   1.453 -		    {
   1.454 -                        if (pswit[ECHO_SWITCH])
   1.455 -			    printf("\n%s\n",aline);
   1.456 -                        if (!pswit[OVERVIEW_SWITCH])
   1.457 -                            printf("    Line %ld column %d - "
   1.458 -			      "Wrongspaced quotes?\n",linecnt,(int)(s-aline)+1);
   1.459 -                        else
   1.460 -                            cnt_punct++;
   1.461 -		    }
   1.462 -		}
   1.463 -	    }
   1.464 -	}
   1.465 -	if (*aline==CHAR_DQUOTE)
   1.466 -	{
   1.467 -	    if (strchr(",;:!?)]} ",aline[1]))
   1.468 -	    {
   1.469 -		if (pswit[ECHO_SWITCH])
   1.470 -		    printf("\n%s\n",aline);
   1.471 -		if (!pswit[OVERVIEW_SWITCH])
   1.472 -		    printf("    Line %ld column 1 - Wrongspaced quotes?\n",
   1.473 -		      linecnt);
   1.474 -		else
   1.475 -		    cnt_punct++;
   1.476 -	    }
   1.477 -	}
   1.478 -        if (pswit[SQUOTE_SWITCH])
   1.479 -	{
   1.480 -            for (s=aline;*s;s++)
   1.481 -	    {
   1.482 -                if ((*s==CHAR_SQUOTE || *s==CHAR_OPEN_SQUOTE) &&
   1.483 -		  (s==aline || s>aline && !gcisalpha(s[-1]) ||
   1.484 -		  !gcisalpha(s[1])))
   1.485 -		{
   1.486 -                    if (!(squotepar=!squotepar))
   1.487 -		    {
   1.488 -			/* parity even */
   1.489 -                        if (!strchr("_-.'`/\",;:!?)]} ",s[1]))
   1.490 -			{
   1.491 -                            if (pswit[ECHO_SWITCH])
   1.492 -				printf("\n%s\n",aline);
   1.493 -                            if (!pswit[OVERVIEW_SWITCH])
   1.494 -                                printf("    Line %ld column %d - "
   1.495 -				  "Wrongspaced singlequotes?\n",
   1.496 -				  linecnt,(int)(s-aline)+1);
   1.497 -                            else
   1.498 -                                cnt_punct++;
   1.499 -			}
   1.500 -		    }
   1.501 -                    else
   1.502 -		    {
   1.503 -			/* parity odd */
   1.504 -                        if (!gcisalpha(s[1]) && !isdigit(s[1]) &&
   1.505 -			  !strchr("_-/\".'`",s[1]) || !s[1])
   1.506 -			{
   1.507 -                            if (pswit[ECHO_SWITCH])
   1.508 -				printf("\n%s\n",aline);
   1.509 -                            if (!pswit[OVERVIEW_SWITCH])
   1.510 -                                printf("    Line %ld column %d - "
   1.511 -				  "Wrongspaced singlequotes?\n",
   1.512 -				  linecnt,(int)(s-aline)+1);
   1.513 -                            else
   1.514 -                                cnt_punct++;
   1.515 -			}
   1.516 -		    }
   1.517 -		}
   1.518 -	    }
   1.519 -	}
   1.520 +	check_for_misspaced_punctuation(aline,&parities,isemptyline);
   1.521          /*
   1.522  	 * Look for double punctuation like ,. or ,,
   1.523           * Thanks to DW for the suggestion!