int main() {
    
    string  input;
    
    while( cin >> N && N ) {

        E.clear();
        
        int x,  y;
        
        while( cin >> x && x ) {
            getline( cin, input );
            istringstream   is( input );
            while( is >> y )
                E.push_back( make_pair( x, y ) );
        }
        
        int cnt = 0;
        
        for( int i = 1; i <= N; ++i ) {
            U.init( N );
            for( int j = 0; j < E.size(); ++j )
                if( E[j].first != i && E[j].second != i )
                    U.merge( E[j].first, E[j].second );
            if( U.getSets() > 2 )
                ++cnt;
        }
        
        cout << cnt << endl; 

    }
    
}
int main() {

    int     T,  N,  V;
    string  S;
    int     IN[26];
    int     OUT[26]; 
    Union<26>   U; 
    
    for( cin >> T; T--; ) {
        
        U.init( 26 ); 
        memset( IN, 0, sizeof( IN ) ); 
        memset( OUT, 0, sizeof( OUT ) ); 
        
        for( cin >> N; N--; ) {
            cin >> S;
            int x = S[0] - 'a',
                y = S[S.size() - 1] - 'a';
            IN[x]++; 
            OUT[y]++; 
            U.merge( x, y );
        } 
        
        bool    yes = true;
        int     cnt = 0;
        for( int i = V = 0; i <26; ++i ) {
            V += IN[i] || OUT[i]; 
            if( IN[i] == OUT[i] )
                continue;
            if( IN[i] - OUT[i] > 1 ||
                IN[i] - OUT[i] < -1 ) {
                yes = false;
                break;
            }
            ++cnt;
        }
        
        if( cnt > 2 || !yes || U.getSets() + V != 27 ) {
            puts( "The door cannot be opened." );
            continue; 
        }
        
        else    puts( "Ordering is possible." );
                
    } 

} 
int main() {
    
    for( cin >> T; T--; ) {
      
        U.init( 26 ); 
        
        for( int i = 0; i < 26; ++i ) {
            G[i].clear(); 
            IN[i] = OUT[i] = 0; 
        }

        for( cin >> N; N--; ) {
            string  input;
            cin >> input;
            int x = input[0] - 'a',
                y = input[input.size() - 1] - 'a';
            IN[x]++;
            OUT[y]++; 
            U.merge( x, y );
            G[x].push_back( input );
        } 

        bool    yes = true;
        int     V = 0,  cnt = 0;
        int     begin_pos = 0; 
        for( int i = 0; i <26; ++i ) {
            V += IN[i] || OUT[i]; 
            if( IN[i] == OUT[i] )
                continue;
            if( IN[i] - OUT[i] > 1 ||
                IN[i] - OUT[i] < -1 ) {
                yes = false;
                break;
            } 
            ++cnt;
            if( IN[i] - OUT[i] == 1 )
                begin_pos = i; 
        }

        // 有两个以上奇度点或者
        // 有不平衡点(出入度相差 1 以上) 或者 
        // 不连通,都判为无欧拉路径 
        if( cnt > 2 || !yes || U.getSets() + V != 27 ) {
            puts( "***" );
            continue; 
        }

        // 下面已经确认有欧拉路径,开始寻路 
        path.clear();
        trace.clear(); 

        // 保证字典序
        for( int i = 0; i < 26; ++i )
            if( G[i].size() > 1 )
                sort( G[i].begin(), G[i].end(), greater<string>() );

        // 注意如果有一个点 入度 = 出度 + 1
        // 必须从这个点开始周游 
        if( begin_pos == 0 )
            while( !IN[begin_pos] && !OUT[begin_pos] )
                ++begin_pos; 
        Tour( begin_pos );

        cout << path.back();
        path.pop_back(); 
        while( path.size() ) {
            cout << '.' << path.back();
            path.pop_back(); 
        }

        cout << endl; 
        
    } 
    
}