Sat Aug 6 00:39:37 2011

Asterisk developer's documentation


app_test.c File Reference

Applications to test connection and produce report in text file. More...

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "asterisk/channel.h"
#include "asterisk/options.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"

Go to the source code of this file.

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int load_module (void)
static int measurenoise (struct ast_channel *chan, int ms, char *who)
static int sendnoise (struct ast_channel *chan, int ms)
static int testclient_exec (struct ast_channel *chan, void *data)
static int testserver_exec (struct ast_channel *chan, void *data)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Interface Test Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, }
static const struct ast_module_infoast_module_info = &__mod_info
static char * testc_app = "TestClient"
static char * testc_descrip
static char * testc_synopsis = "Execute Interface Test Client"
static char * tests_app = "TestServer"
static char * tests_descrip
static char * tests_synopsis = "Execute Interface Test Server"


Detailed Description

Applications to test connection and produce report in text file.

Author:
Mark Spencer <markster@digium.com>

Russell Bryant <russelb@clemson.edu>

Definition in file app_test.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 512 of file app_test.c.

static void __unreg_module ( void   )  [static]

Definition at line 512 of file app_test.c.

static int load_module ( void   )  [static]

Definition at line 502 of file app_test.c.

References ast_register_application(), testclient_exec(), and testserver_exec().

00503 {
00504    int res;
00505 
00506    res = ast_register_application(testc_app, testclient_exec, testc_synopsis, testc_descrip);
00507    res |= ast_register_application(tests_app, testserver_exec, tests_synopsis, tests_descrip);
00508 
00509    return res;
00510 }

static int measurenoise ( struct ast_channel chan,
int  ms,
char *  who 
) [static]

Definition at line 64 of file app_test.c.

References AST_FORMAT_SLINEAR, AST_FRAME_VOICE, ast_frfree, ast_log(), ast_read(), ast_set_read_format(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), f, LOG_DEBUG, LOG_NOTICE, and ast_channel::readformat.

Referenced by testclient_exec(), and testserver_exec().

00065 {
00066    int res=0;
00067    int mssofar;
00068    int noise=0;
00069    int samples=0;
00070    int x;
00071    short *foo;
00072    struct timeval start;
00073    struct ast_frame *f;
00074    int rformat;
00075    rformat = chan->readformat;
00076    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
00077       ast_log(LOG_NOTICE, "Unable to set to linear mode!\n");
00078       return -1;
00079    }
00080    start = ast_tvnow();
00081    for(;;) {
00082       mssofar = ast_tvdiff_ms(ast_tvnow(), start);
00083       if (mssofar > ms)
00084          break;
00085       res = ast_waitfor(chan, ms - mssofar);
00086       if (res < 1)
00087          break;
00088       f = ast_read(chan);
00089       if (!f) {
00090          res = -1;
00091          break;
00092       }
00093       if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
00094          foo = (short *)f->data;
00095          for (x=0;x<f->samples;x++) {
00096             noise += abs(foo[x]);
00097             samples++;
00098          }
00099       }
00100       ast_frfree(f);
00101    }
00102 
00103    if (rformat) {
00104       if (ast_set_read_format(chan, rformat)) {
00105          ast_log(LOG_NOTICE, "Unable to restore original format!\n");
00106          return -1;
00107       }
00108    }
00109    if (res < 0)
00110       return res;
00111    if (!samples) {
00112       ast_log(LOG_NOTICE, "No samples were received from the other side!\n");
00113       return -1;
00114    }
00115    ast_log(LOG_DEBUG, "%s: Noise: %d, samples: %d, avg: %d\n", who, noise, samples, noise / samples);
00116    return (noise / samples);
00117 }

static int sendnoise ( struct ast_channel chan,
int  ms 
) [static]

Definition at line 119 of file app_test.c.

References ast_tonepair_start(), ast_tonepair_stop(), and ast_waitfordigit().

Referenced by testclient_exec(), and testserver_exec().

00120 {
00121    int res;
00122    res = ast_tonepair_start(chan, 1537, 2195, ms, 8192);
00123    if (!res) {
00124       res = ast_waitfordigit(chan, ms);
00125       ast_tonepair_stop(chan);
00126    }
00127    return res;
00128 }

static int testclient_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 130 of file app_test.c.

References ast_channel::_state, ast_answer(), ast_app_getdata(), ast_config_AST_LOG_DIR, ast_dtmf_stream(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_safe_sleep(), AST_STATE_UP, ast_strlen_zero(), ast_waitfordigit(), ast_module_user::chan, f, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, measurenoise(), ast_channel::name, option_debug, and sendnoise().

Referenced by load_module().

00131 {
00132    struct ast_module_user *u;
00133    int res = 0;
00134    char *testid=data;
00135    char fn[80];
00136    char serverver[80];
00137    FILE *f;
00138 
00139    /* Check for test id */
00140    if (ast_strlen_zero(testid)) {
00141       ast_log(LOG_WARNING, "TestClient requires an argument - the test id\n");
00142       return -1;
00143    }
00144 
00145    u = ast_module_user_add(chan);
00146 
00147    if (chan->_state != AST_STATE_UP)
00148       res = ast_answer(chan);
00149 
00150    /* Wait a few just to be sure things get started */
00151    res = ast_safe_sleep(chan, 3000);
00152    /* Transmit client version */
00153    if (!res)
00154       res = ast_dtmf_stream(chan, NULL, "8378*1#", 0);
00155    if (option_debug)
00156       ast_log(LOG_DEBUG, "Transmit client version\n");
00157 
00158    /* Read server version */
00159    if (option_debug)
00160       ast_log(LOG_DEBUG, "Read server version\n");
00161    if (!res)
00162       res = ast_app_getdata(chan, NULL, serverver, sizeof(serverver) - 1, 0);
00163    if (res > 0)
00164       res = 0;
00165    if (option_debug)
00166       ast_log(LOG_DEBUG, "server version: %s\n", serverver);
00167    if (res > 0)
00168       res = 0;
00169    if (!res)
00170       res = ast_safe_sleep(chan, 1000);
00171    /* Send test id */
00172    if (!res)
00173       res = ast_dtmf_stream(chan, NULL, testid, 0);
00174    if (!res)
00175       res = ast_dtmf_stream(chan, NULL, "#", 0);
00176    if (option_debug)
00177       ast_log(LOG_DEBUG, "send test identifier: %s\n", testid);
00178 
00179    if ((res >=0) && (!ast_strlen_zero(testid))) {
00180       /* Make the directory to hold the test results in case it's not there */
00181       snprintf(fn, sizeof(fn), "%s/testresults", ast_config_AST_LOG_DIR);
00182       mkdir(fn, 0777);
00183       snprintf(fn, sizeof(fn), "%s/testresults/%s-client.txt", ast_config_AST_LOG_DIR, testid);
00184       if ((f = fopen(fn, "w+"))) {
00185          setlinebuf(f);
00186          fprintf(f, "CLIENTCHAN:    %s\n", chan->name);
00187          fprintf(f, "CLIENTTEST ID: %s\n", testid);
00188          fprintf(f, "ANSWER:        PASS\n");
00189          res = 0;
00190 
00191          if (!res) {
00192             /* Step 1: Wait for "1" */
00193             if (option_debug)
00194                ast_log(LOG_DEBUG, "TestClient: 2.  Wait DTMF 1\n");
00195             res = ast_waitfordigit(chan, 3000);
00196             fprintf(f, "WAIT DTMF 1:   %s\n", (res != '1') ? "FAIL" : "PASS");
00197             if (res == '1')
00198                res = 0;
00199             else
00200                res = -1;
00201          }
00202          if (!res) {
00203             res = ast_safe_sleep(chan, 1000);
00204          }
00205          if (!res) {
00206             /* Step 2: Send "2" */
00207             if (option_debug)
00208                ast_log(LOG_DEBUG, "TestClient: 2.  Send DTMF 2\n");
00209             res = ast_dtmf_stream(chan, NULL, "2", 0);
00210             fprintf(f, "SEND DTMF 2:   %s\n", (res < 0) ? "FAIL" : "PASS");
00211             if (res > 0)
00212                res = 0;
00213          }
00214          if (!res) {
00215             /* Step 3: Wait one second */
00216             if (option_debug)
00217                ast_log(LOG_DEBUG, "TestClient: 3.  Wait one second\n");
00218             res = ast_safe_sleep(chan, 1000);
00219             fprintf(f, "WAIT 1 SEC:    %s\n", (res < 0) ? "FAIL" : "PASS");
00220             if (res > 0)
00221                res = 0;
00222          }
00223          if (!res) {
00224             /* Step 4: Measure noise */
00225             if (option_debug)
00226                ast_log(LOG_DEBUG, "TestClient: 4.  Measure noise\n");
00227             res = measurenoise(chan, 5000, "TestClient");
00228             fprintf(f, "MEASURENOISE:  %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
00229             if (res > 0)
00230                res = 0;
00231          }
00232          if (!res) {
00233             /* Step 5: Wait for "4" */
00234             if (option_debug)
00235                ast_log(LOG_DEBUG, "TestClient: 5.  Wait DTMF 4\n");
00236             res = ast_waitfordigit(chan, 3000);
00237             fprintf(f, "WAIT DTMF 4:   %s\n", (res != '4') ? "FAIL" : "PASS");
00238             if (res == '4')
00239                res = 0;
00240             else
00241                res = -1;
00242          }
00243          if (!res) {
00244             /* Step 6: Transmit tone noise */
00245             if (option_debug)
00246                ast_log(LOG_DEBUG, "TestClient: 6.  Transmit tone\n");
00247             res = sendnoise(chan, 6000);
00248             fprintf(f, "SENDTONE:      %s\n", (res < 0) ? "FAIL" : "PASS");
00249          }
00250          if (!res || (res == '5')) {
00251             /* Step 7: Wait for "5" */
00252             if (option_debug)
00253                ast_log(LOG_DEBUG, "TestClient: 7.  Wait DTMF 5\n");
00254             if (!res)
00255                res = ast_waitfordigit(chan, 3000);
00256             fprintf(f, "WAIT DTMF 5:   %s\n", (res != '5') ? "FAIL" : "PASS");
00257             if (res == '5')
00258                res = 0;
00259             else
00260                res = -1;
00261          }
00262          if (!res) {
00263             /* Step 8: Wait one second */
00264             if (option_debug)
00265                ast_log(LOG_DEBUG, "TestClient: 8.  Wait one second\n");
00266             res = ast_safe_sleep(chan, 1000);
00267             fprintf(f, "WAIT 1 SEC:    %s\n", (res < 0) ? "FAIL" : "PASS");
00268             if (res > 0)
00269                res = 0;
00270          }
00271          if (!res) {
00272             /* Step 9: Measure noise */
00273             if (option_debug)
00274                ast_log(LOG_DEBUG, "TestClient: 9.  Measure tone\n");
00275             res = measurenoise(chan, 4000, "TestClient");
00276             fprintf(f, "MEASURETONE:   %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
00277             if (res > 0)
00278                res = 0;
00279          }
00280          if (!res) {
00281             /* Step 10: Send "7" */
00282             if (option_debug)
00283                ast_log(LOG_DEBUG, "TestClient: 10.  Send DTMF 7\n");
00284             res = ast_dtmf_stream(chan, NULL, "7", 0);
00285             fprintf(f, "SEND DTMF 7:   %s\n", (res < 0) ? "FAIL" : "PASS");
00286             if (res > 0)
00287                res =0;
00288          }
00289          if (!res) {
00290             /* Step 11: Wait for "8" */
00291             if (option_debug)
00292                ast_log(LOG_DEBUG, "TestClient: 11.  Wait DTMF 8\n");
00293             res = ast_waitfordigit(chan, 3000);
00294             fprintf(f, "WAIT DTMF 8:   %s\n", (res != '8') ? "FAIL" : "PASS");
00295             if (res == '8')
00296                res = 0;
00297             else
00298                res = -1;
00299          }
00300          if (!res) {
00301             res = ast_safe_sleep(chan, 1000);
00302          }
00303          if (option_debug && !res ) {
00304             /* Step 12: Hangup! */
00305             ast_log(LOG_DEBUG, "TestClient: 12.  Hangup\n");
00306          }
00307 
00308          if (option_debug)
00309             ast_log(LOG_DEBUG, "-- TEST COMPLETE--\n");
00310          fprintf(f, "-- END TEST--\n");
00311          fclose(f);
00312          res = -1;
00313       } else
00314          res = -1;
00315    } else {
00316       ast_log(LOG_NOTICE, "Did not read a test ID on '%s'\n", chan->name);
00317       res = -1;
00318    }
00319    ast_module_user_remove(u);
00320    return res;
00321 }

static int testserver_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 323 of file app_test.c.

References ast_channel::_state, ast_answer(), ast_app_getdata(), ast_config_AST_LOG_DIR, ast_dtmf_stream(), ast_log(), ast_module_user_add, ast_module_user_remove, ast_safe_sleep(), AST_STATE_UP, ast_strlen_zero(), ast_waitfordigit(), ast_module_user::chan, f, LOG_DEBUG, LOG_NOTICE, measurenoise(), ast_channel::name, option_debug, and sendnoise().

Referenced by load_module().

00324 {
00325    struct ast_module_user *u;
00326    int res = 0;
00327    char testid[80]="";
00328    char fn[80];
00329    FILE *f;
00330    u = ast_module_user_add(chan);
00331    if (chan->_state != AST_STATE_UP)
00332       res = ast_answer(chan);
00333    /* Read version */
00334    if (option_debug)
00335       ast_log(LOG_DEBUG, "Read client version\n");
00336    if (!res)
00337       res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
00338    if (res > 0)
00339       res = 0;
00340    if (option_debug) {
00341       ast_log(LOG_DEBUG, "client version: %s\n", testid);
00342       ast_log(LOG_DEBUG, "Transmit server version\n");
00343    }
00344    res = ast_safe_sleep(chan, 1000);
00345    if (!res)
00346       res = ast_dtmf_stream(chan, NULL, "8378*1#", 0);
00347    if (res > 0)
00348       res = 0;
00349 
00350    if (!res)
00351       res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
00352    if (option_debug)
00353       ast_log(LOG_DEBUG, "read test identifier: %s\n", testid);
00354    /* Check for sneakyness */
00355    if (strchr(testid, '/'))
00356       res = -1;
00357    if ((res >=0) && (!ast_strlen_zero(testid))) {
00358       /* Got a Test ID!  Whoo hoo! */
00359       /* Make the directory to hold the test results in case it's not there */
00360       snprintf(fn, sizeof(fn), "%s/testresults", ast_config_AST_LOG_DIR);
00361       mkdir(fn, 0777);
00362       snprintf(fn, sizeof(fn), "%s/testresults/%s-server.txt", ast_config_AST_LOG_DIR, testid);
00363       if ((f = fopen(fn, "w+"))) {
00364          setlinebuf(f);
00365          fprintf(f, "SERVERCHAN:    %s\n", chan->name);
00366          fprintf(f, "SERVERTEST ID: %s\n", testid);
00367          fprintf(f, "ANSWER:        PASS\n");
00368          ast_log(LOG_DEBUG, "Processing Test ID '%s'\n", testid);
00369          res = ast_safe_sleep(chan, 1000);
00370          if (!res) {
00371             /* Step 1: Send "1" */
00372             if (option_debug)
00373                ast_log(LOG_DEBUG, "TestServer: 1.  Send DTMF 1\n");
00374             res = ast_dtmf_stream(chan, NULL, "1", 0);
00375             fprintf(f, "SEND DTMF 1:   %s\n", (res < 0) ? "FAIL" : "PASS");
00376             if (res > 0)
00377                res = 0;
00378          }
00379          if (!res) {
00380             /* Step 2: Wait for "2" */
00381             if (option_debug)
00382                ast_log(LOG_DEBUG, "TestServer: 2.  Wait DTMF 2\n");
00383             res = ast_waitfordigit(chan, 3000);
00384             fprintf(f, "WAIT DTMF 2:   %s\n", (res != '2') ? "FAIL" : "PASS");
00385             if (res == '2')
00386                res = 0;
00387             else
00388                res = -1;
00389          }
00390          if (!res) {
00391             /* Step 3: Measure noise */
00392             if (option_debug)
00393                ast_log(LOG_DEBUG, "TestServer: 3.  Measure noise\n");
00394             res = measurenoise(chan, 6000, "TestServer");
00395             fprintf(f, "MEASURENOISE:  %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
00396             if (res > 0)
00397                res = 0;
00398          }
00399          if (!res) {
00400             /* Step 4: Send "4" */
00401             if (option_debug)
00402                ast_log(LOG_DEBUG, "TestServer: 4.  Send DTMF 4\n");
00403             res = ast_dtmf_stream(chan, NULL, "4", 0);
00404             fprintf(f, "SEND DTMF 4:   %s\n", (res < 0) ? "FAIL" : "PASS");
00405             if (res > 0)
00406                res = 0;
00407          }
00408          if (!res) {
00409             /* Step 5: Wait one second */
00410             if (option_debug)
00411                ast_log(LOG_DEBUG, "TestServer: 5.  Wait one second\n");
00412             res = ast_safe_sleep(chan, 1000);
00413             fprintf(f, "WAIT 1 SEC:    %s\n", (res < 0) ? "FAIL" : "PASS");
00414             if (res > 0)
00415                res = 0;
00416          }
00417          if (!res) {
00418             /* Step 6: Measure noise */
00419             if (option_debug)
00420                ast_log(LOG_DEBUG, "TestServer: 6.  Measure tone\n");
00421             res = measurenoise(chan, 4000, "TestServer");
00422             fprintf(f, "MEASURETONE:   %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
00423             if (res > 0)
00424                res = 0;
00425          }
00426          if (!res) {
00427             /* Step 7: Send "5" */
00428             if (option_debug)
00429                ast_log(LOG_DEBUG, "TestServer: 7.  Send DTMF 5\n");
00430             res = ast_dtmf_stream(chan, NULL, "5", 0);
00431             fprintf(f, "SEND DTMF 5:   %s\n", (res < 0) ? "FAIL" : "PASS");
00432             if (res > 0)
00433                res = 0;
00434          }
00435 
00436          if (!res) {
00437             /* Step 8: Transmit tone noise */
00438             if (option_debug)
00439                ast_log(LOG_DEBUG, "TestServer: 8.  Transmit tone\n");
00440             res = sendnoise(chan, 6000);
00441             fprintf(f, "SENDTONE:      %s\n", (res < 0) ? "FAIL" : "PASS");
00442          }
00443 
00444          if (!res || (res == '7')) {
00445             /* Step 9: Wait for "7" */
00446             if (option_debug)
00447                ast_log(LOG_DEBUG, "TestServer: 9.  Wait DTMF 7\n");
00448             if (!res)
00449                res = ast_waitfordigit(chan, 3000);
00450             fprintf(f, "WAIT DTMF 7:   %s\n", (res != '7') ? "FAIL" : "PASS");
00451             if (res == '7')
00452                res = 0;
00453             else
00454                res = -1;
00455          }
00456          if (!res) {
00457             res = ast_safe_sleep(chan, 1000);
00458          }
00459          if (!res) {
00460             /* Step 10: Send "8" */
00461             if (option_debug)
00462                ast_log(LOG_DEBUG, "TestServer: 10.  Send DTMF 8\n");
00463             res = ast_dtmf_stream(chan, NULL, "8", 0);
00464             fprintf(f, "SEND DTMF 8:   %s\n", (res < 0) ? "FAIL" : "PASS");
00465             if (res > 0)
00466                res = 0;
00467          }
00468          if (!res) {
00469             /* Step 11: Wait for hangup to arrive! */
00470             if (option_debug)
00471                ast_log(LOG_DEBUG, "TestServer: 11.  Waiting for hangup\n");
00472             res = ast_safe_sleep(chan, 10000);
00473             fprintf(f, "WAIT HANGUP:   %s\n", (res < 0) ? "PASS" : "FAIL");
00474          }
00475 
00476          ast_log(LOG_NOTICE, "-- TEST COMPLETE--\n");
00477          fprintf(f, "-- END TEST--\n");
00478          fclose(f);
00479          res = -1;
00480       } else
00481          res = -1;
00482    } else {
00483       ast_log(LOG_NOTICE, "Did not read a test ID on '%s'\n", chan->name);
00484       res = -1;
00485    }
00486    ast_module_user_remove(u);
00487    return res;
00488 }

static int unload_module ( void   )  [static]

Definition at line 490 of file app_test.c.

References ast_module_user_hangup_all, and ast_unregister_application().

00491 {
00492    int res;
00493 
00494    res = ast_unregister_application(testc_app);
00495    res |= ast_unregister_application(tests_app);
00496 
00497    ast_module_user_hangup_all();
00498 
00499    return res;
00500 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Interface Test Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } [static]

Definition at line 512 of file app_test.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 512 of file app_test.c.

char* testc_app = "TestClient" [static]

Definition at line 61 of file app_test.c.

char* testc_descrip [static]

Initial value:

    "TestClient(testid): Executes test client with given testid.\n"
    "Results stored in /var/log/asterisk/testreports/<testid>-client.txt"

Definition at line 57 of file app_test.c.

char* testc_synopsis = "Execute Interface Test Client" [static]

Definition at line 62 of file app_test.c.

char* tests_app = "TestServer" [static]

Definition at line 54 of file app_test.c.

char* tests_descrip [static]

Initial value:

    "TestServer(): Perform test server function and write call report.\n"
    "Results stored in /var/log/asterisk/testreports/<testid>-server.txt"

Definition at line 51 of file app_test.c.

char* tests_synopsis = "Execute Interface Test Server" [static]

Definition at line 55 of file app_test.c.


Generated on Sat Aug 6 00:39:37 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7