let (N, M) = readInts().mapToTuple()

struct Root: Equatable {
    let a, b: Int

    func other(of id: Int) -> Int? {
        if a == id { return b }
        if b == id { return a }
        return nil
    }
}

var roots: [Root] = (1...M).map { i in
    let (a, b) = readInts().mapToTuple()
    return Root(a: a, b: b)
}

var rooms = Array(repeating: Optional<Int>.none, count: N)

rooms[0] = 0
var old: Set<Int> = [1]
var now = [1]
while !now.isEmpty {
    for i in now {
        let rs = roots
            .compactMap { $0.other(of: i) }
            .filter { !old.contains($0) }
//        print(rs)
        old.formUnion(rs)
        now = rs
        for j in rs {
            rooms[j-1] = i
        }
    }
}

//print(rooms)
if rooms.allSatisfy({ $0 != nil }) {
    print("Yes")
    rooms[1...].forEach { print($0!) }
} else {
    print("No")
}

// MARK: -----------------------------------------------------------------------

func readInts() -> [Int] {
    readLine()!.split(separator: " ").map { Int($0)! }
}

extension Collection {
    func mapToTuple() -> (Element, Element) {
        var i = makeIterator()
        return (i.next()!, i.next()!)
    }
    func mapToTuple() -> (Element, Element, Element) {
        var i = makeIterator()
        return (i.next()!, i.next()!, i.next()!)
    }
    func mapToTuple() -> (Element, Element, Element, Element) {
        var i = makeIterator()
        return (i.next()!, i.next()!, i.next()!, i.next()!)
    }

    subscript(gen: Index) -> Element {
        _modify { yield &self[index(gen, offsetBy: -1)] }
        _read   { yield self[index(gen, offsetBy: -1)] }
    }
}


let (N, M) = readInts().mapToTuple()

struct Room: Equatable {
    let id: Int
    var roots = [Int]()
    var flags: Int?
}

struct Root: Equatable {
    let a, b: Int

    func other(of id: Int) -> Int? {
        if a == id { return b }
        if b == id { return a }
        return nil
    }
}

var roots: [Root] = (1...M).map { i in
    let (a, b) = readInts().mapToTuple()
    return Root(a: a, b: b)
}

var rooms: [Room] = (1...N).map { Room(id: $0) }

rooms[0].flags = 0
var old: Set<Int> = [1]
var now = [1]
while !now.isEmpty {
    for i in now {
        let rs = roots
            .compactMap { $0.other(of: i) }
            .filter { !old.contains($0) }
//        print(rs)
        old.formUnion(rs)
        now = rs
        for j in rs {
            rooms[j-1].flags = i
        }
    }
}

//print(rooms)
if rooms.allSatisfy({ $0.flags != nil }) {
    print("Yes")
    rooms[1...].forEach { print($0.flags!) }
} else {
    print("No")
}

// MARK: -----------------------------------------------------------------------

func readInts() -> [Int] {
    readLine()!.split(separator: " ").map { Int($0)! }
}

extension Collection {
    func mapToTuple() -> (Element, Element) {
        var i = makeIterator()
        return (i.next()!, i.next()!)
    }
    func mapToTuple() -> (Element, Element, Element) {
        var i = makeIterator()
        return (i.next()!, i.next()!, i.next()!)
    }
    func mapToTuple() -> (Element, Element, Element, Element) {
        var i = makeIterator()
        return (i.next()!, i.next()!, i.next()!, i.next()!)
    }
}

struct DP<Argument: Hashable, Element> {
    var dictionary = [Argument: Element]()

    var expression: (Argument, (Argument) -> Element) -> Element

    init(expression: @escaping (_ argument: Argument, _ note: (Argument) -> Element) -> Element) {
        self.expression = expression
    }

    subscript(_ argument: Argument) -> Element {
        mutating get {
            if let note = dictionary[argument] {
                return note
            } else {
                let result = expression(argument) { self[$0] }
                dictionary[argument] = result
                return result
            }
        }
    }
}


import * as fs from 'fs';

const readString = (() => {
  const input = fs.readFileSync(0).toString();
  const words = input.split(/[ \n]/);
  let i = 0;
  return () => words[i++] || '';
})();
const readInt = () => parseInt(readString(), 10);

(function main() {
  const N = readInt();
  const M = readInt();
  const routes: { [n: number]: number[] } = {}
  const pairs = Array.from({ length: M }, () => {
    const A = readInt();
    const B = readInt();
    routes[A] = routes[A] || [];
    routes[A].push(B);
    routes[B] = routes[B] || [];
    routes[B].push(A);
  });
  const depth: { [n: number]: number } = { 1: 1 };
  const parent: { [n: number]: number } = {};
  const paths: number[] = [1];
  while (true) {
    const n = paths.pop();
    if (n == null) break;

    const rs = routes[n];
    for (const r of rs) {
      if (depth[r] == null) {
        depth[r] = depth[n] + 1;
        parent[r] = n;
        paths.unshift(r);
      }
    }
  }

  console.log('Yes');
  for (let i = 2; i <= N; i++) {
    console.log(parent[i]);
  }
})();


import { readFileSync } from "fs";

const read = () =>
  readFileSync(0, "utf8")
    .split("\n")
    .map((line) => line.split(" "));

const main = (input: string[][]) => {
  const [N, M] = input[0].map(Number);

  const adjacencies = [...Array(N + 1)].map(() => Array<number>());
  for (let i = 1; i <= M; i++) {
    const [A, B] = input[i].map(Number);

    adjacencies[A].unshift(B);
    adjacencies[B].unshift(A);
  }

  const distances: number[] = [];
  const parents: number[] = [];

  distances[1] = 0;

  const queue = [1];
  while (true) {
    const current = queue.pop();
    if (current === undefined) {
      break;
    }

    adjacencies[current].forEach((adjacency) => {
      if (distances[adjacency] !== undefined) {
        return;
      }

      distances[adjacency] = distances[current] + 1;
      parents[adjacency] = current;

      queue.unshift(adjacency);
    });
  }

  return `Yes\n${parents.slice(2).join("\n")}`;
};

console.log(main(read()));


import { count } from 'console';

process.stdin.resume();
process.stdin.setEncoding('utf8');

// 標準入力取込
let gInput = '';
process.stdin.on('data', (chunk) => (gInput += chunk));
process.stdin.on('end', () => main(gInput.split(/\r?\n/)));

// 解答
function main(inputs: string[]): void {
  const [n, m] = inputs[0].split(' ').map(Number);
  let room: number[][] = Array.from(new Array(n), () => new Array());
  let rootList: number[][][] = new Array();
  let result: number[] = new Array();

  // 各部屋から移動できる部屋番号を格納
  for (let i = 1; i <= m; i++) {
    const [a, b] = inputs[i].split(' ').map(Number);

    room[a - 1].push(b);
    room[b - 1].push(a);
  }

  // 各部屋のルート探索
  for (let i = 1; i < n; i++) {
    const targetRoom = room[i];

    // 移動できる部屋が存在しない場合、エラー
    if (targetRoom.length === 0) {
      noExistRootMessage();
      return;
    }
    // ループするルート(-1のルート)を除いて、配列へ格納
    rootList.push(searchRoot(i + 1, [], room).filter((value) => value[0] !== -1));
  }

  // 部屋1に最小の移動回数で辿り着く次の部屋を格納
  for (const root of rootList) {
    if (root.length == 0) {
      noExistRootMessage();
      return;
    }

    let minCount = -1;
    let roomNumber = 0;

    for (const targetRoot of root) {
      if (minCount === -1 || minCount > targetRoot.length) {
        minCount = targetRoot.length;
        roomNumber = targetRoot[1];
      }
    }
    result.push(roomNumber);
  }

  console.log('Yes');
  result.forEach((value) => console.log(value));
}

function noExistRootMessage() {
  console.log('No');
}

// 各部屋のルートを全探索
// ループするルートは-1を返す
function searchRoot(roomNumber: number, root: number[], room: number[][]): number[][] {
  if (root.indexOf(roomNumber) !== -1) {
    return [[-1]];
  }

  if (roomNumber === 1) {
    root.push(1);
    return [root];
  }

  let rootList: number[][] = [];
  const nextRoom = room[roomNumber - 1];
  for (const nextRoomNumber of nextRoom) {
    rootList = rootList.concat(searchRoot(nextRoomNumber, root.concat(roomNumber), room));
  }
  return rootList;
}


import { count } from 'console';

process.stdin.resume();
process.stdin.setEncoding('utf8');

// 標準入力取込
let gInput = '';
process.stdin.on('data', (chunk) => (gInput += chunk));
process.stdin.on('end', () => main(gInput.split(/\r?\n/)));

// 解答
function main(inputs: string[]): void {
  const [n, m] = inputs[0].split(' ').map(Number);
  let room: number[][] = Array.from(new Array(m), () => new Array());
  let rootList: number[][][] = new Array();
  let result: number[] = new Array();

  // 各部屋から移動できる部屋番号を格納
  for (let i = 1; i <= m; i++) {
    const [a, b] = inputs[i].split(' ').map(Number);

    room[a - 1].push(b);
    room[b - 1].push(a);
  }

  // 各部屋のルート探索
  for (let i = 1; i < n; i++) {
    const targetRoom = room[i];

    // 移動できる部屋が存在しない場合、エラー
    if (targetRoom.length === 0) {
      noExistRootMessage();
      return;
    }
    // ループするルート(-1を含む)を除いて、配列へ格納
    rootList.push(
      searchRoot(i + 1, [], room).filter((value) => value[0] !== -1 && value.indexOf(1) >= 0),
    );
  }

  // 部屋1に最小の移動回数で辿り着く次の部屋を格納
  for (const root of rootList) {
    if (root.length == 0) {
      noExistRootMessage();
      return;
    }

    let minCount = -1;
    let roomNumber = 0;

    for (const targetRoot of root) {
      if (minCount === -1 || minCount > targetRoot.length) {
        minCount = targetRoot.length;
        roomNumber = targetRoot[1];
      }
    }
    result.push(roomNumber);
  }

  console.log('Yes');
  result.forEach((value) => console.log(value));
}

function noExistRootMessage() {
  console.log('No');
}

// 各部屋のルートを全探索
// ループするルートは-1を返す
function searchRoot(roomNumber: number, root: number[], room: number[][]): number[][] {
  if (root.indexOf(roomNumber) !== -1) {
    return [[-1]];
  }

  if (roomNumber === 1) {
    root.push(1);
    return [root];
  }

  let rootList: number[][] = [];
  const nextRoom = room[roomNumber - 1];
  for (const nextRoomNumber of nextRoom) {
    rootList = rootList.concat(searchRoot(nextRoomNumber, root.concat(roomNumber), room));
  }
  return rootList;
}


import { count } from 'console';

process.stdin.resume();
process.stdin.setEncoding('utf8');

// 標準入力取込
let gInput = '';
process.stdin.on('data', (chunk) => (gInput += chunk));
process.stdin.on('end', () => main(gInput.split(/\r?\n/)));

// 解答
function main(inputs: string[]): void {
  const [n, m] = inputs[0].split(' ').map(Number);
  let room: number[][] = Array.from(new Array(m), () => new Array());
  let rootList: number[][][] = new Array();
  let result: number[] = new Array();

  // 各部屋から移動できる部屋番号を格納
  for (let i = 1; i <= m; i++) {
    const [a, b] = inputs[i].split(' ').map(Number);

    room[a - 1].push(b);
    room[b - 1].push(a);
  }

  // 各部屋のルート探索
  for (let i = 1; i < n; i++) {
    const targetRoom = room[i];

    // 移動できる部屋が存在しない場合、エラー
    if (targetRoom.length === 0) {
      noExistRootMessage();
      return;
    }
    // ループするルート(-1を含む)を除いて、配列へ格納
    rootList.push(searchRoot(i + 1, [], room).filter((value) => value[0] !== -1));
  }

  // 部屋1に最小の移動回数で辿り着く次の部屋を格納
  for (const root of rootList) {
    if (root.length == 0) {
      noExistRootMessage();
      return;
    }

    let minCount = -1;
    let roomNumber = 0;

    for (const targetRoot of root) {
      if (minCount === -1 || minCount > targetRoot.length) {
        minCount = targetRoot.length;
        roomNumber = targetRoot[1];
      }
    }
    result.push(roomNumber);
  }

  console.log('Yes');
  result.forEach((value) => console.log(value));
}

function noExistRootMessage() {
  console.log('No');
}

// 各部屋のルートを全探索
// ループするルートは-1を返す
function searchRoot(roomNumber: number, root: number[], room: number[][]): number[][] {
  if (root.indexOf(roomNumber) !== -1) {
    return [[-1]];
  }

  if (roomNumber === 1) {
    root.push(1);
    return [root];
  }

  let rootList: number[][] = [];
  const nextRoom = room[roomNumber - 1];
  for (const nextRoomNumber of nextRoom) {
    rootList = rootList.concat(searchRoot(nextRoomNumber, root.concat(roomNumber), room));
  }
  return rootList;
}


import sys
import collections
import itertools

def resolve(in_):
    one = ord(b'1')
    two = ord(b'2')
    # print(f'{one=} {two=}')

    S = in_.readline().strip()
    q = collections.deque(S)
    # print(f'{S=} {q=}')

    reverse_flag = False
    Q = int(in_.readline())
    for query in itertools.islice(in_, Q):
        T = query[0]
        if T == one:
            reverse_flag ^= True
            # q.reverse()
        elif T == two:
            F = query[2]
            C = query[4]
            if (F == one) ^ reverse_flag:
                q.appendleft(C)
            else:
                q.append(C)
    else:
        if reverse_flag:
            q.reverse()
            reverse_flag = 0

    return bytes(q)

def main():
    answer = resolve(sys.stdin.buffer)
    print(answer.decode('ascii'))

if __name__ == '__main__':
    main()


import sys
import collections
import itertools

def resolve(in_):
    one = ord(b'1')
    two = ord(b'2')
    # print(f'{one=} {two=}')

    S = in_.readline().strip()
    q = collections.deque(S)
    # print(f'{S=} {q=}')

    reverse_flag = False
    Q = int(in_.readline())
    for query in itertools.islice(in_, Q):
        T = query[0]
        if T == one:
            reverse_flag ^= True
            # q.reverse()
        elif T == two:
            F = query[2]
            C = query[4]
            if (F == one) ^ reverse_flag:
                q.appendleft(C)
            else:
                q.append(C)

    return bytes(reversed(q)) if reverse_flag else bytes(q)

def main():
    answer = resolve(sys.stdin.buffer)
    print(answer.decode('ascii'))

if __name__ == '__main__':
    main()


# D - String Formation
import sys
from collections import deque

readline = sys.stdin.readline
readlines = sys.stdin.readlines

def main():
    S = readline().rstrip()
    _ = readline()
    queries = readlines()
    queue = deque(S)
    to_beginning, to_end = queue.appendleft, queue.append
    is_reversed = 0
    for query in queries:
        if query[0] == "1":
            to_beginning, to_end = to_end, to_beginning
            is_reversed ^= 1
            continue
        com, c = query[2], query[4]
        if com == "1":
            to_beginning(c)
        else:
            to_end(c)
    ans = "".join(queue) if not is_reversed else "".join(reversed(queue))
    print(ans)

if __name__ == "__main__":
    main()


S = input()
Q = int(input())

for i in range(Q):
    Query = input().split()
    if len(Query) == 1:
        S = S[::-1]
    else:
        if Query[1] == "1":
            S = Query[2] + S
        else:
            S = S + Query[2]

print(S)


S = str(input())
Q = int(input())
Qvery = [0]*Q
for i in range(Q):
    Qvery[i] = list(map(str,input().split()))
frontback = 1
tail = ''
head = ''
for i in range(Q):
    if Qvery[i][0]=='1':
        frontback *= -1

    else:
        if Qvery[i][1]=='2':
            if frontback == 1:
                tail +=  str(Qvery[i][2])
            else:
                head = str(Qvery[i][2]) + head
        else:
            if frontback == 1:
                head = str(Qvery[i][2])+head
            else:
                tail += str(Qvery[i][2])
if frontback == -1:
    S = S[::-1]

print(head+S+tail)


if __name__ == '__main__':
    S = list(input())
    Q = int(input())
    for _ in range(Q):
        qry = input().split(' ')
        if len(qry) == 3:
            f = int(qry[1])
            c = qry[2]
            if f == 1:
                S.insert(0, c)
            if f == 2:
                S.append(c)
        if len(qry) == 1:
            tmp = S[0]
            S[0] = S[-1]
            S[-1] = tmp
    ans = ''
    for s in S:
        ans += s
    print(ans)


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.InputMismatchException;
import java.util.Iterator;
import java.util.NoSuchElementException;

public class Main {
    static void solve(MyScanner in, MyWriter out) {
        String s = in.next();
        int q = in.nextInt();
        boolean reversed = false;
        StringBuilder head = new StringBuilder();
        StringBuilder tail = new StringBuilder();
        for (int i = 0; i < q; i++) {
            int t = in.nextInt();
            if (t == 1) {
                reversed = !reversed;
            } else {
                int f = in.nextInt();
                char c = in.nextChar();
                if (reversed) {
                    if (f == 1) {
                        tail.append(c);
                    } else {
                        head.append(c);
                    }
                } else {
                    if (f == 1) {
                        head.append(c);
                    } else {
                        tail.append(c);
                    }
                }
            }
        }
        StringBuilder ans = new StringBuilder();
        if (reversed) {
            tail.reverse();
            ans.append(tail)
               .append(new StringBuilder(s).reverse())
               .append(head);
        } else {
            head.reverse();
            ans.append(head).append(s).append(tail);
        }
        out.println(ans.toString());
    }
    public static void main(String[] args) {
        MyWriter w = new MyWriter(System.out);
        solve(new MyScanner(System.in), w);
        w.flush();
    }
    static final class MyScanner {
        static final int BUFFER_SIZE = 8192;
        private final InputStream in;
        private final byte[] buffer = new byte[BUFFER_SIZE];
        private int point;
        private int readLength;

        MyScanner(InputStream in) {
            this.in = in;
        }
        private byte readByte() {
            if (point < readLength) {
                byte result = buffer[point];
                point += 1;
                return result;
            }
            try {
                readLength = in.read(buffer);
            } catch (IOException e) {
                throw new AssertionError(null, e);
            }
            if (readLength == -1) {
                return -1;
            }
            point = 1;
            return buffer[0];
        }
        private static boolean isPrintableCharExceptSpace(byte c) {
            return 33 <= c && c <= 126;
        }
        public char nextChar() {
            byte c = readByte();
            while (!(c == -1 || isPrintableCharExceptSpace(c))) {
                c = readByte();
            }
            if (c == -1) {
                throw new NoSuchElementException();
            }
            return (char)c;
        }
        public String next() {
            return next(16);
        }
        public String next(int n) {
            byte c = readByte();
            while (!(c == -1 || isPrintableCharExceptSpace(c))) {
                c = readByte();
            }
            if (c == -1) {
                throw new NoSuchElementException();
            }
            StringBuilder b = new StringBuilder(n);
            do {
                b.append((char)c);
                c = readByte();
            } while (c != -1 && isPrintableCharExceptSpace(c));
            return b.toString();
        }
        public long nextLong() {
            byte c = readByte();
            while (!(c == -1 || isPrintableCharExceptSpace(c))) {
                c = readByte();
            }
            if (c == -1) {
                throw new NoSuchElementException();
            }
            boolean minus = false;
            if (c == '-') {
                minus = true;
                c = readByte();
            }
            long result = 0L;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                result = result * 10L + (c - '0');
                c = readByte();
            } while (c != -1 && isPrintableCharExceptSpace(c));
            return minus ? -result : result;
        }
        public int nextInt() {
            long n = nextLong();
            if (n < Integer.MIN_VALUE || n > Integer.MAX_VALUE) {
                throw new InputMismatchException();
            }
            return (int)n;
        }
        public double nextDouble() {
            return Double.parseDouble(next());
        }
        public int[] nextIntArray(int n) {
            int[] result = new int[n];
            for (int i = 0; i < n; i++) {
                result[i] = nextInt();
            }
            return result;
        }
        public long[] nextLongArray(int n) {
            long[] result = new long[n];
            for (int i = 0; i < n; i++) {
                result[i] = nextLong();
            }
            return result;
        }
        public char[] nextCharArray(int n) {
            char[] result = new char[n];
            for (int i = 0; i < n; i++) {
                result[i] = nextChar();
            }
            return result;
        }
        public char[][] next2dCharArray(int n, int m) {
            char[][] result = new char[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    result[i][j] = nextChar();
                }
            }
            return result;
        }
        public int[][] nextVerticalIntArrays(int arrayCount, int arrayLength) {
            int[][] result = new int[arrayCount][arrayLength];
            for (int i = 0; i < arrayLength; i++) {
                for (int j = 0; j < arrayCount; j++) {
                    result[j][i] = nextInt();
                }
            }
            return result;
        }
        public long[][] nextVerticalLongArrays(int arrayCount,
                                               int arrayLength) {
            long[][] result = new long[arrayCount][arrayLength];
            for (int i = 0; i < arrayLength; i++) {
                for (int j = 0; j < arrayCount; j++) {
                    result[j][i] = nextLong();
                }
            }
            return result;
        }
        public char[][] nextVerticalCharArrays(int arrayCount,
                                               int arrayLength) {
            char[][] result = new char[arrayCount][arrayLength];
            for (int i = 0; i < arrayLength; i++) {
                for (int j = 0; j < arrayCount; j++) {
                    result[j][i] = nextChar();
                }
            }
            return result;
        }
    }
    static final class MyWriter extends PrintWriter {
        MyWriter(OutputStream out) {
            super(out);
        }
        public void joinAndPrintln(int[] x) {
            joinAndPrintln(x, " ");
        }
        public void joinAndPrintln(int[] x, String delimiter) {
            StringBuilder b = new StringBuilder();
            if (x.length > 0) {
                b.append(x[0]);
                for (int i = 1; i < x.length; i++) {
                    b.append(delimiter).append(x[i]);
                }
            }
            println(b.toString());
        }
        public void joinAndPrintln(long[] x) {
            joinAndPrintln(x, " ");
        }
        public void joinAndPrintln(long[] x, String delimiter) {
            StringBuilder b = new StringBuilder();
            if (x.length > 0) {
                b.append(x[0]);
                for (int i = 1; i < x.length; i++) {
                    b.append(delimiter).append(x[i]);
                }
            }
            println(b.toString());
        }
        public void joinAndPrintln(Iterable<?> iterable) {
            joinAndPrintln(iterable, " ");
        }
        public void joinAndPrintln(Iterable<?> iterable, String delimiter) {
            StringBuilder b = new StringBuilder();
            for (Iterator<?> i = iterable.iterator(); i.hasNext();) {
                b.append(i.next());
                while (i.hasNext()) {
                    b.append(delimiter).append(i.next());
                }
            }
            println(b.toString());
        }
    }
}


import java.io.*;
import java.util.*;

class Main {
    public static void main(String args[]) throws IOException {
        Scan sc = new Scan();
        LinkedList<Character> str = new LinkedList<>();
        int n = sc.scan();
        while(!sc.isWhiteSpace(n))
        {
            str.add((char)n);
            n=sc.scan();
        }

        int q= sc.scanInt();
        int revPar = 0;
        while(q-- > 0){
            int type = sc.scanInt();
            if(type == 1){
                revPar ^= 1;
            }
            else {
                int type2 = (sc.scanInt()-1)^revPar;
                char val = sc.scanChar();
                if(type2 == 0){
                    str.addFirst(val);
                }
                else
                    str.add(val);
            }
        }
        StringBuilder sb = new StringBuilder();
        for(char c : str)
            sb.append(c);
        if(revPar == 1)
            sb.reverse();
        System.out.println(sb);
    }
}

class Scan
{
    private byte[] buf=new byte[1024];
    private int index;
    private InputStream in;
    private int total;
    public Scan()
    {
        in=System.in;
    }
    public int scan()throws IOException
    {
        if(total<0)
        throw new InputMismatchException();
        if(index>=total)
        {
            index=0;
            total=in.read(buf);
            if(total<=0)
            return -1;
        }
        return buf[index++];
    }
    public char scanChar() throws IOException {
        int n = scan();
        while(isWhiteSpace(n))
            n=scan();
        return (char)n;
    }
    public int scanInt()throws IOException
    {
        int integer=0;
        int n=scan();
        while(isWhiteSpace(n))
        n=scan();
        int neg=1;
        if(n=='-')
        {
            neg=-1;
            n=scan();
        }
        while(!isWhiteSpace(n))
        {
            if(n>='0'&&n<='9')
            {
                integer*=10;
                integer+=n-'0';
                n=scan();
            }
            else throw new InputMismatchException();
        }
        return neg*integer;
    }
    public long scanLong() throws IOException {
        long integer=0;
        int n=scan();
        while(isWhiteSpace(n))
        n=scan();
        int neg=1;
        if(n=='-')
        {
            neg=-1;
            n=scan();
        }
        while(!isWhiteSpace(n))
        {
            if(n>='0'&&n<='9')
            {
                integer*=10;
                integer+=n-'0';
                n=scan();
            }
            else throw new InputMismatchException();
        }
        return neg*integer;
    }
    public double scanDouble()throws IOException
    {
        double doub=0;
        int n=scan();
        while(isWhiteSpace(n))
        n=scan();
        int neg=1;
        if(n=='-')
        {
            neg=-1;
            n=scan();
        }
        while(!isWhiteSpace(n)&&n!='.')
        {
            if(n>='0'&&n<='9')
            {
                doub*=10;
                doub+=n-'0';
                n=scan();
            }
            else throw new InputMismatchException();
        }
        if(n=='.')
        {
            n=scan();
            double temp=1;
            while(!isWhiteSpace(n))
            {
                if(n>='0'&&n<='9')
                {
                    temp/=10;
                    doub+=(n-'0')*temp;
                    n=scan();
                }
                else throw new InputMismatchException();
            }
        }
        return doub*neg;
    }
    public String scanString()throws IOException
    {
        StringBuilder sb=new StringBuilder();
        int n=scan();
        while(isWhiteSpace(n))
        n=scan();
        while(!isWhiteSpace(n))
        {
            sb.append((char)n);
            n=scan();
        }
        return sb.toString();
    }
    public boolean isWhiteSpace(int n)
    {
        if(n==' '||n=='\n'||n=='\r'||n=='\t'||n==-1)
        return true;
        return false;
    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        DStringFormation solver = new DStringFormation();
        solver.solve(1, in, out);
        out.close();
    }

    static class DStringFormation {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            String s = in.nextString();
            int q = in.nextInt();
            int ar[] = new int[q];
            int f = 0;
            StringBuilder sb1 = new StringBuilder();
            StringBuilder sb2 = new StringBuilder();
            while (q-- > 0) {
                int t = in.nextInt();
                if (t == 1) {
                    f++;
                    continue;
                }
                int k = in.nextInt();
                String e = in.nextString();
                if (k == 1 && f % 2 == 0)
                    sb2.append(e);
                if (k == 1 && f % 2 == 1)
                    sb1.append(e);
                if (k == 2 && f % 2 == 0)
                    sb1.append(e);
                if (k == 2 && f % 2 == 1)
                    sb2.append(e);
            }
            StringBuilder sb3 = new StringBuilder(s);
            if (f % 2 == 1) {
                sb3.append(sb1);
                sb3.reverse();
                out.println();
                sb3.append(sb2);
                String st = sb3.toString();
                out.println(st);
            } else {
                sb2.reverse();
                sb2.append(sb3).append(sb1);
                String st = sb2.toString();
                out.println(st);
            }
        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

        public void println() {
            writer.println();
        }

        public void println(Object... objects) {
            print(objects);
            writer.println();
        }

        public void close() {
            writer.close();
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int nextInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public String nextString() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            StringBuilder res = new StringBuilder();
            do {
                if (Character.isValidCodePoint(c)) {
                    res.appendCodePoint(c);
                }
                c = read();
            } while (!isSpaceChar(c));
            return res.toString();
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        char[] s = sc.next().toCharArray();
        int n = sc.nextInt();
        Deque<Character> deq = new ArrayDeque<>();
        for (int i = 0; i < s.length; i++) {
            deq.addLast(s[i]);
        }
        boolean flg = false;
        for (int i = 0; i < n; i++) {
            int t = sc.nextInt();
            if(t == 1) {
                if(flg) {
                    flg = false;
                } else {
                    flg = true;
                }
            } else if(t == 2) {
                int f = sc.nextInt();
                char c = sc.next().charAt(0);
                if(flg && f == 1) {
                    deq.addFirst(c);
                } else if(!flg && f == 1) {
                    deq.addLast(c);
                } else if(flg && f == 2) {
                    deq.addLast(c);
                } else if(!flg && f == 2) {
                    deq.addFirst(c);
                }
            }
        }
        if(!flg) {
            while(!deq.isEmpty()) {
                System.out.print(deq.pollLast());
            }
        } else {
            while(!deq.isEmpty()) {
                System.out.print(deq.pollFirst());
            }
        }
    }
}


import java.util.Scanner;

public class Main {

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		StringBuffer s = new StringBuffer(sc.next());
		int q = sc.nextInt();

		for (int i = 0; i < q; i++) {
			int t = sc.nextInt();
			if (t == 1) {
				s.reverse();
			} else {
				i ++;
				int f = sc.nextInt();
				String c = sc.next();

				if (f == 1) {
					s.insert(0, c);
				} else {
					s.append(c);
				}
			}
		}
		System.out.println(s);
	}

}


import java.util.Scanner;

public class Main {

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		StringBuffer s = new StringBuffer(sc.next());
		int q = sc.nextInt();

		for (int i = 0; i < q; i++) {
			int t = sc.nextInt();
			if (t == 1) {
				s.reverse();
			} else {
				i += 2;
				int f = sc.nextInt();
				String c = sc.next();

				if (f == 1) {
					s.insert(0, c);
				} else {
					s.append(c);
				}
			}
		}
		System.out.println(s);
	}

}


#pragma GCC optimize ("O3")
#pragma GCC target ("avx")
//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i = 0; i < (n); i++)
#define rep1(i, n) for(int i = 1; i <= (n); i++)
#define co(x) cout << (x) << "\n"
#define cosp(x) cout << (x) << " "
#define ce(x) cerr << (x) << "\n"
#define cesp(x) cerr << (x) << " "
#define pb push_back
#define mp make_pair
#define chmin(x, y) x = min(x, y)
#define chmax(x, y) x = max(x, y)
#define Would
#define you
#define please

char S[1300020];
char S2[200000];
int main() {
	//cin.tie(0);
	//ios::sync_with_stdio(false);

	fread(S, 1, 1300020, stdin);

	int L = -1;
	int R = 99999;
	while (L + 1 < R) {
		int H = (L + R) / 2;
		if (S[H] >= 'a' && S[H + 1] >= 'a') L = H;
		else R = H;
	}
	int N = R + 1;
	char* ci = S + N + 1;
	char ct;
	int Q = 0;
	while ((ct = *ci++) >= '0') Q = Q * 10 + ct - '0';

	L = 0;
	R = Q + 1;
	while (L + 1 < R) {
		int H = (L + R) / 2;
		if (*(ci + H * 4 + 2 * Q - 2) >= '0') L = H;
		else R = H;
	}
	int kazu = L;
	bool dotti = (Q - kazu) % 2;

	ci += 4;

	if (dotti) {
		char* smae = S2, * sato = S2 + kazu;
		bool gyaku = 0;
		rep(i, Q) {
			char c = *ci;
			if (c < 'a') {
				ci += 2;
				gyaku = !gyaku;
			}
			else {
				bool f = *(ci - 2) - '1';
				if (f ^ gyaku)* --sato = c;
				else *smae++ = c;
				ci += 6;
			}
		}
		reverse(S, S + N);
		fwrite(sato, 1, kazu - (sato - S2), stdout);
		fwrite(S, 1, N, stdout);
		fwrite(S2, 1, smae - S2, stdout);
	}
	else {
		char* smae = S2 + kazu, * sato = S2;
		bool gyaku = 0;
		rep(i, Q) {
			char c = *ci;
			if (c < 'a') {
				ci += 2;
				gyaku = !gyaku;
			}
			else {
				bool f = *(ci - 2) - '1';
				if (f ^ gyaku)* sato++ = c;
				else *--smae = c;
				ci += 6;
			}
		}
		fwrite(smae, 1, kazu - (smae - S2), stdout);
		fwrite(S, 1, N, stdout);
		fwrite(S2, 1, sato - S2, stdout);
	}

	Would you please return 0;
}


#pragma GCC optimize ("O3")
#pragma GCC target ("avx")
//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i = 0; i < (n); i++)
#define rep1(i, n) for(int i = 1; i <= (n); i++)
#define co(x) cout << (x) << "\n"
#define cosp(x) cout << (x) << " "
#define ce(x) cerr << (x) << "\n"
#define cesp(x) cerr << (x) << " "
#define pb push_back
#define mp make_pair
#define chmin(x, y) x = min(x, y)
#define chmax(x, y) x = max(x, y)
#define Would
#define you
#define please

char S[1300020];
char S2[200000];
int main() {
	//cin.tie(0);
	//ios::sync_with_stdio(false);

	fread(S, 1, 1300020, stdin);

	int saidai = strlen(S);
	int L = -1;
	int R = min(int(strlen(S)) - 2, 99999);
	while (L + 1 < R) {
		int H = (L + R) / 2;
		if (S[H] >= 'a' && S[H + 1] >= 'a') L = H;
		else R = H;
	}
	int N = R + 1;
	char* ci = S + N + 1;
	char ct;
	int Q = 0;
	while ((ct = *ci++) >= '0') Q = Q * 10 + ct - '0';

	int nagasa = saidai - (ci - S) + 1;
	nagasa -= Q * 2;
	int kazu = nagasa / 4;
	bool dotti = (Q - kazu) % 2;

	ci += 4;

	if (dotti) {
		char* smae = S2, * sato = S2 + kazu;
		bool gyaku = 0;
		rep(i, Q) {
			char c = *ci;
			if (c < 'a') {
				ci += 2;
				gyaku = !gyaku;
			}
			else {
				bool f = *(ci - 2) - '1';
				if (f ^ gyaku)* --sato = c;
				else *smae++ = c;
				ci += 6;
			}
		}
		reverse(S, S + N);
		fwrite(sato, 1, kazu - (sato - S2), stdout);
		fwrite(S, 1, N, stdout);
		fwrite(S2, 1, smae - S2, stdout);
	}
	else {
		char* smae = S2 + kazu, * sato = S2;
		bool gyaku = 0;
		rep(i, Q) {
			char c = *ci;
			if (c < 'a') {
				ci += 2;
				gyaku = !gyaku;
			}
			else {
				bool f = *(ci - 2) - '1';
				if (f ^ gyaku)* sato++ = c;
				else *--smae = c;
				ci += 6;
			}
		}
		fwrite(smae, 1, kazu - (smae - S2), stdout);
		fwrite(S, 1, N, stdout);
		fwrite(S2, 1, sato - S2, stdout);
	}

	Would you please return 0;
}


#pragma GCC optimize ("O3")
#pragma GCC target ("avx")
//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i = 0; i < (n); i++)
#define rep1(i, n) for(int i = 1; i <= (n); i++)
#define co(x) cout << (x) << "\n"
#define cosp(x) cout << (x) << " "
#define ce(x) cerr << (x) << "\n"
#define cesp(x) cerr << (x) << " "
#define pb push_back
#define mp make_pair
#define chmin(x, y) x = min(x, y)
#define chmax(x, y) x = max(x, y)
#define Would
#define you
#define please

int main() {
	//cin.tie(0);
	//ios::sync_with_stdio(false);

	char S[1300010];
	char S2[200000];
	fread(S, 1, 1300010, stdin);

	int saidai = strlen(S);
	int L = -1;
	int R = min(int(strlen(S)) - 2, 99999);
	while (L + 1 < R) {
		int H = (L + R) / 2;
		if (S[H] >= 'a' && S[H + 1] >= 'a') L = H;
		else R = H;
	}
	int N = R + 1;
	char* ci = S + N + 1;
	char ct;
	int Q = 0;
	while ((ct = *ci++) >= '0') Q = Q * 10 + ct - '0';
	char* smae = S2, * sato = S2 + Q;

	bool gyaku = 0;
	rep(i, Q) {
		if (*ci == '1') {
			ci += 2;
			gyaku = !gyaku;
		}
		else {
			ci += 2;
			bool f = *ci - '1';
			ci += 2;
			if (f ^ gyaku) *--sato = *ci;
			else *smae++ = *ci;
			ci += 2;
		}
	}

	auto kato = S2 + Q - sato;
	auto kmae = smae - S2;

	if (gyaku) {
		reverse(S, S + N);
		fwrite(sato, 1, kato, stdout);
		fwrite(S, 1, N, stdout);
		fwrite(S2, 1, kmae, stdout);
	}
	else {
		reverse(S2, S2 + Q);
		fwrite(S2 + Q - kmae, 1, kmae, stdout);
		fwrite(S, 1, N, stdout);
		fwrite(S2, 1, kato, stdout);
	}

	Would you please return 0;
}


#include <bits/stdc++.h>
using namespace std;

int main(){
string s,t;
int64_t a,b,c,d;
  b=0;
cin>>s>>a;
for(int64_t i=0;i<a;i++){
   cin>>c;
  if(c==1){b++;}
  if(c==2){
    cin>>d>>t;
    if((b+d)%2==1){s=t+s;}
    else{s=s+t;}
  }
}
if(b%2==0){cout<<s<<endl;}
else{
  for(int64_t i=0;i<s.size();i++){
    cout<<s.at(s.size()-1-i);
  }
  cout<<endl;
  }
}


#include <bits/stdc++.h>
using namespace std;

int main(){
string s,t;
int64_t a,b,c,d;
cin>>s>>a;
for(int64_t i=0;i<a;i++){
   cin>>c;
  if(c==1){b++;}
  if(c==2){cin>>d>>t;
          if((b+d)%2==1){s=t+s;}
          else{s=s+t;}}}
if(b%2==0){cout<<s<<endl;}
else{
  vector<char> vec(s.size());
  for(int64_t i=0;i<s.size();i++){
      vec.at(i)=s.at(s.size()-1-i);
  }
  for(int64_t i=0;i<s.size();i++){
    cout<<vec.at(i);
  }
  cout<<endl;
  }
}


#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>

using namespace std;
typedef long long ll;

int main(){
  string S;
  ll Q;
  cin >> S;
  cin >> Q;
  vector<char> s;
  for(ll i=0;i<S.length();i++){
    s.push_back(S[i]);
  }
  ll T[Q];
  vector<ll> q(Q);
  vector<char> p(Q);
  for(ll i=0;i<Q;i++){
    cin >> T[i];
    if(T[i]==1){
      q[i]=0;
    }else{
      cin >> q[i] >> p[i];
    }
  }
  bool flag = true;
  for(ll i=0;i<Q;i++){
    if(T[i]==1){
      flag = !flag;
    }else{
      if(flag){
	if(q[i]==1){
	  s.push_back(p[i]);
	}else{
	  s.insert(s.begin(),p[i]);
	}
      }else{
	if(q[i]==1){
	  s.insert(s.begin(),p[i]);
	}else{
	  s.push_back(p[i]);
	}
      }
    }
  }
  if(!flag){
    for(ll i=0;i<s.size();i++){
      cout << s[i];
    }
  }else{
    for(ll i=s.size()-1;i>=0;i--){
      cout << s[i];
    }
  }
  cout << endl;
}


// ABC 158-D
// 2020.3.7 bal4u

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int in() {   // 非負整数の入力
	int n = 0; int c;
	c = gc();
	do n = 10 * n + (c & 0xf); while ((c = gc()) >= '0');
	return n;
}

int ins(char *s) { // 文字列の入力　スペース以下の文字で入力終了
	char *p = s--;
	do *++s = gc();
	while (*s > ' ');
	*s = 0;
	return s - p;
}

char S[600005], *a, *b;

int main()
{
	int Q, rev, id, F, C;

	a = S+250000;
	b = a + ins(a);
	rev = 0;
	Q = in();
	while (Q--) {
		id = gc(), gc();
		if (id == '1') rev = !rev;
		else {
			F = gc(), gc();
			C = gc(), gc();
			if (F == '1') {
				if (rev) *b++ = C;
				else *--a = C;
			} else {
				if (rev) *--a = C;
				else *b++ = C;
			}
		}
	}
	if (rev) {
		while (b > a) pc(*--b);
	} else {
		while (a < b) pc(*a++);
	}
	pc('\n');
	return 0;
}


#include <stdio.h>
#include <stdlib.h>

typedef struct p_tag{
    char c;
    struct p_tag *prev;
    struct p_tag *next;
} string;

int main(){
    char str[100002];
    int qn;
    int i;
    char q[10];
    int rot = 0;
    string *head, *tail, *buf, *buf_prev=NULL;

    (void)fgets(str, 100002, stdin);

    i = 0;
    while(str[i] != '\n'){
        buf = malloc(sizeof(string));
        if(i == 0){
            head = buf;
        }
        buf->c = str[i];
        buf->prev = buf_prev;
        buf->next = NULL;
        if(buf_prev != NULL){
            buf_prev->next = buf;
        }
        buf_prev = buf;
        i++;
    };
    tail = buf;

    (void)scanf("%d", &qn);
    (void)getchar();

    for(i=0; i < qn; i++){
        (void)fgets(q, 10, stdin);
        if(q[0] == '1'){
            rot++;
        }else{
            if(q[2] == '1' && rot % 2 == 0 || q[2] == '2' && rot % 2 == 1){
                buf = malloc(sizeof(string));
                buf->c = q[4];
                buf->next = head;
                buf->prev = NULL;
                head->prev = buf;
                head = buf;
            }else{
                buf = malloc(sizeof(string));
                buf->c = q[4];
                buf->next = NULL;
                buf->prev = tail;
                tail->next = buf;
                tail = buf;
            }
        }
    }
    if(rot % 2 == 0){
        putchar(head->c);
        while(1){
            head = head->next;
            if(head == NULL){
                putchar('\n');
                return 0;
            }
            putchar(head->c);
        }
    }else{
        putchar(tail->c);
        while(1){
            tail = tail->prev;
            if(tail == NULL){
                putchar('\n');
                return 0;
            }
            putchar(tail->c);
        }
    }
}


#include<stdio.h>
#include<string.h>

int main()
{
	char ch,s[300009],f[200009],r[200009];
	gets(s);
	int len=strlen(s);
	int front=0,rear=0,q,i,t,order,now=1;
	scanf("%d",&q);

	for (i=1;i<=q;i++)
	{
		scanf("%d",&t);
		if (t==1) now=1-now;
		else
		{
			scanf("%d",&order);
			if (order==1)
			{
				if (now==1)
				{
					++front;
					ch=getchar();
					f[front]=getchar();
				}
				else
				{
					++rear;
					ch=getchar();
					r[rear]=getchar();
				}
			}
			else
			{
				if (now==0)
				{
					++front;
					ch=getchar();
					f[front]=getchar();
				}
				else
				{
					++rear;
					ch=getchar();
					r[rear]=getchar();
				}
			}
		}
	}

	if (now==1)
	{
		for (i=front;i>=1;i--)
			putchar(f[i]);
		for (i=0;i<len;i++)
			putchar(s[i]);
		for (i=1;i<=rear;i++)
			putchar(r[i]);
	}
	else
	{
		for (i=rear;i>=1;i--)
			putchar(r[i]);
		for (i=len-1;i>=0;i--)
			putchar(s[i]);
		for (i=1;i<=front;i++)
			putchar(f[i]);
	}

	return 0;
}


#include <stdio.h>
#include <string.h>
#define MAXCHAR 100005

char word[MAXCHAR];
void reverse(int left, int right);

int main ()
{
    char c[3];
    int q, f, t;
    scanf("%s", word);
    scanf("%d", &q);

    for (int i = 0; i < q; i++)
    {
        scanf("%d", &t);
        if (t == 1)
        {
            int j = 0;
            while (word[j] != '\0')
                j++;
            reverse(0, j - 1);
        }
        else if (t == 2)
        {
            scanf("%d %[^\n]", &f, c);
            if (f == 2)
            {
                strcat(word, c);
            }
            else
            {
                strcat(c, word);
                strcpy(word, c);
            }
        }
    }

    printf("%s\n", word);

    return 0;
}

void swap(char *a, char *b)
{
    char temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

void reverse(int left, int right)
{
    while (right - left > 0)
    {
        swap(&word[left], &word[right]);
        right--;
        left++;
    }
}


#include <stdio.h>
#define MAXCHAR 100005

static char word[MAXCHAR];

void addToBack (char);
void addToFront (char);
void reverse (int, int);

int main ()
{
    char c;
    int q, f, t;
    scanf("%s", word);
    scanf("%d", &q);

    for (int i = 0; i < q; i++)
    {
        scanf("%d", &t);
        if (t == 1)
        {
            int j = 0;
            while (word[j] != '\0')
                j++;
            reverse(0, j - 1);
        }
        else if (t == 2)
        {
            scanf("%d %c", &f, &c);
            getchar();
            if (f == 2)
            {
                addToBack(c);
            }
            else
            {
                addToFront(c);
            }
        }
    }

    printf("%s\n", word);

    return 0;
}

void addToBack(char c)
{
    int j = 0;
    while (word[j] != '\0')
        j++;
    word[j] = c;
    word[j + 1] = '\0';
}

void addToFront(char c)
{
    int j = 0;
    while (word[j] != '\0')
        j++;

    int len = --j;
    while (j >= 0)
    {
        word[j + 1] = word[j];
        j--;
    }
    word[0] = c;
    word[len + 2] = '\0';
}

void swap (char *a, char *b)
{
    char temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

void reverse (int left, int right)
{
    while (right - left > 0)
    {
        swap(&word[left], &word[right]);
        right--;
        left++;
    }
}


#include <stdio.h>
#define MAXCHAR 100005

char word[MAXCHAR];

void addToBack (char, int);
void addToFront (char, int);
void reverse (int, int);

int main ()
{
    char c;
    int q, f, t;
    scanf("%s", word);
    scanf("%d", &q);

    for (int i = 0; i < q; i++)
    {
        scanf("%d", &t);
        int j;
        if (t == 1)
        {
            j = 0;
            while (word[j] != '\0')
                j++;
            reverse(0, j - 1);
        }
        else if (t == 2)
        {
            scanf("%d %c", &f, &c);
            getchar();
            if (f == 2)
            {
                j = 0;
                while (word[j] != '\0')
                    j++;
                addToBack(c, j);
            }
            else
            {
                j = 0;
                while (word[j] != '\0')
                    j++;
                addToFront(c, --j);
            }
        }
    }

    printf("%s\n", word);

    return 0;
}

void addToBack(char c, int n)
{
    word[n] = c;
    word[n + 1] = '\0';
}

void addToFront(char c, int n)
{
    int len = n;
    while (n >= 0)
    {
        word[n + 1] = word[n];
        n--;
    }
    word[0] = c;
    word[len + 2] = '\0';
}

void swap (char *a, char *b)
{
    char temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

void reverse (int left, int right)
{
    while (right - left > 0)
    {
        swap(&word[left], &word[right]);
        right--;
        left++;
    }
}


"use strict";
var input = require("fs").readFileSync("/dev/stdin", "utf8");
var cin = input.split(/ |\n/),
    cid = 0;

// number一個取得
// eslint-disable-next-line no-unused-vars
const next = () => +cin[cid++];

// 文字列一個取得
// eslint-disable-next-line no-unused-vars
const nextstr = () => cin[cid++];

// BigInteger一個取得
// eslint-disable-next-line no-unused-vars
const nextbig = () => BigInt(cin[cid++]);

// 長さnの配列として取得。aは文字列フラグ
// eslint-disable-next-line no-unused-vars
const nexts = (n, a) =>
    a ? cin.slice(cid, (cid += n)) : cin.slice(cid, (cid += n)).map((a) => +a);

// w個ずつを組にして長さhの配列。aは文字列フラグ。
// eslint-disable-next-line no-unused-vars
const nextm = (h, w, a) => {
    var r = [],
        i = 0;
    if (a) for (; i < h; i++) r.push(cin.slice(cid, (cid += w)));
    else for (; i < h; i++) r.push(cin.slice(cid, (cid += w)).map((a) => +a));
    return r;
};
// 多次元配列。v,a1,a2,a3 なら、3次元。[[値vで長さa3の配列]をa2個並べた配列]をa1個並べた配列。
// eslint-disable-next-line no-unused-vars
const xArray = (...args) => {
    var a = args,
        l = a.length,
        r = "Array(a[" + --l + "]).fill().map(x=>{return " + a[0] + ";})";
    while (--l) r = "Array(a[" + l + "]).fill().map(x=>" + r + ")";
    return eval(r);
};
main();

function main() {
    let S = nextstr();
    let Q = next();
    let hanten = false;
    let mae = [];
    let ato = [];
    for (let i = 0; i < Q; i++) {
        let type = next();
        //console.log("type:", type);
        if (type == 1) {
            hanten = !hanten;
        } else {
            let F = next();
            //console.log("F:", F);
            if ((F == 1 && !hanten) || (F == 2 && hanten)) {
                mae.push(nextstr());
            } else {
                ato.push(nextstr());
            }
        }
    }
    let ans = "";
    if (!hanten) {
        ans = mae.reverse().join("") + S + ato.join("");
    } else {
        ans =
            ato.reverse().join("") +
            S.split("").reverse().join("") +
            mae.join("");
    }
    console.log(ans);
    return;
}


"use strict";

const main = arg => {
    const input = arg.trim().split("\n");

    let s = input[0].split("");
    const QN = parseInt(input[1]);
    let front = []
    let back = []
    let isReverse = false
    for(let i = 2; i<2+QN; i++){
        let q = input[i].split(" ")
        if(q[0] == 1){
            isReverse = !isReverse
        } else {
            if(q[1] == 1){
                if(isReverse) back.push(q[2])
                else front.push(q[2])
            } else {
                if(isReverse) front.push(q[2])
                else back.push(q[2])
            }
        }
    }
    if(isReverse){
        s.reverse()
        back.reverse()
        console.log(back.join("") + s.join("") + front.join(""))
    }else{
        front.reverse()
        console.log(front.join("")+s.join("")+back.join(""))
    }
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));


"use strict"
function main(arg) {
    var data = arg.trim().split("\n")
    var str = data[0]
    data.shift()
    data.shift()
    var is_omote = true
    for (var i = 0; i < data.length; i++) {
        var row = data[i].split(' ')
        if (row[0] === '1') {
            is_omote = !is_omote
        }
        if (row[0] === '2') {
            if (row[1] === '1') {
                if (is_omote) {
                    // str.unshift(row[2])
                    str = row[2] + str
                }else {
                    // str.push(row[2])
                    str += row[2]
                }
            }
            if (row[1] === '2') {
                if (is_omote) {
                    str += row[2]
                    // str.push(row[2])
                }else {
                    str = row[2] + str
                    // str.unshift(row[2])
                }
            }
        }
    }
    if (!is_omote) {
        str = str.split('').reverse().join('')
    }
    console.log(str)
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));


function Main(input) {
  input=input.split("\n");
  if(input[input.length-1]===''){
    input.pop();
  }
  var S=input[0];
  var reverse=false;
  var top=[];
  var below=[];
  for(var i=2;i<input.length;i++){
    if(input[i][0]==='1'){
      reverse=!reverse;
    }else if(input[i][2]==='1'^reverse){
      top.unshift(input[i].slice(4));
    }else{
      below.push(input[i].slice(4));
    }
  }
  S=top.join('')+S+below.join('');
  if(reverse){
    S=S.split('').reverse().join('');
  }
  console.log(S);
}

//*この行以降は編集しないでください（標準入出力から一度に読み込み、Mainを呼び出します）
Main(require("fs").readFileSync("/dev/stdin", "utf8"));


function Main(input) {
  input=input.split("\n");
  if(input[input.length-1]===''){
    input.pop();
  }
  var S=input[0];
  for(var i=2;i<input.length;i++){
    if(input[i][0]==='1'){
      S=S.split('').reverse().join('');
    }else if(input[i][2]==='1'){
      S=input[i].slice(4)+S;
    }else{
      S+=input[i].slice(4);
    }
  }
  console.log(S);
}

//*この行以降は編集しないでください（標準入出力から一度に読み込み、Mainを呼び出します）
Main(require("fs").readFileSync("/dev/stdin", "utf8"));


function Main(input) {
  input = input.trim().split("\n").map(function(x) { return x.split(" ")});
  var S = input[0];
  var Q = parseInt(input[1], 10);
  //var arr_qu;
  var nReverse = 0;
  var addHead = [];
  var addTail = [];
  for (var i = 0; i < Q; i++){
    if (input[i + 2][0] === '1') {
      nReverse ++;
      continue;
    }
    if ((parseInt(input[i + 2][1], 10) + nReverse) % 2 ===0) {
      addTail.push(input[i + 2][2]);
      continue;
    }
    addHead.unshift(input[i + 2][2]);
  }
  var ans = addHead.concat(S[0].split(""), addTail);
  if (nReverse % 2 === 1) ans = ans.reverse();
  console.log(ans.join(""));
}

Main(require("fs").readFileSync("/dev/stdin", "utf8"));


package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func solve(sc *scanner, wr *bufio.Writer) {
	s := sc.getString()
	q := sc.getInt()

	rolling := false
	var fb, rb strings.Builder
	for i := 0; i < q; i++ {
		switch t := sc.getInt(); t {
		case 1:
			rolling = !rolling
		case 2:
			f := sc.getInt()
			c := sc.getString()
			if rolling {
				if f == 1 {
					rb.WriteString(c)
				} else {
					fb.WriteString(c)
				}
			} else {
				if f == 1 {
					fb.WriteString(c)
				} else {
					rb.WriteString(c)
				}
			}
		}
	}

	reverse := func(s string) string {
		var b strings.Builder
		for i := len(s) - 1; i >= 0; i-- {
			b.WriteByte(s[i])
		}
		return b.String()
	}

	front := reverse(fb.String())
	rear := rb.String()

	ans := front + s + rear
	if rolling {
		ans = reverse(ans)
	}
	fmt.Fprintln(wr, ans)
}

func main() {
	sc := newScanner()
	wr := bufio.NewWriter(os.Stdout)
	maxBufSize := int(1e8)
	sc.Buffer(make([]byte, 4096), maxBufSize)
	sc.Split(bufio.ScanWords)

	solve(sc, wr)
	wr.Flush()
}

// input ------------------------
type scanner struct {
	*bufio.Scanner
}

func newScanner() *scanner {
	sc := bufio.NewScanner(os.Stdin)
	return &scanner{sc}
}
func (sc *scanner) getInt() int {
	sc.Scan()
	ret, err := strconv.Atoi(sc.Text())
	if err != nil {
		panic(err)
	}
	return ret
}
func (sc *scanner) getInt2() (int, int) {
	return sc.getInt(), sc.getInt()
}
func (sc *scanner) getInt3() (int, int, int) {
	return sc.getInt(), sc.getInt(), sc.getInt()
}
func (sc *scanner) getInt4() (int, int, int, int) {
	return sc.getInt(), sc.getInt(), sc.getInt(), sc.getInt()
}
func (sc *scanner) getInts(n int) []int {
	ret := make([]int, n)
	for i := range ret {
		ret[i] = sc.getInt()
	}
	return ret
}
func (sc *scanner) getString() string {
	sc.Scan()
	return sc.Text()
}
func (sc *scanner) getRunes() []rune {
	return []rune(sc.getString())
}
func (sc *scanner) getFloat() float64 {
	sc.Scan()
	ret, err := strconv.ParseFloat(sc.Text(), 64)
	if err != nil {
		panic(err)
	}
	return ret
}
func (sc *scanner) getFloats(n int) []float64 {
	ret := make([]float64, n)
	for i := range ret {
		ret[i] = sc.getFloat()
	}
	return ret
}

// math ----------------------------
func sum(ns ...int) int {
	var sum int
	for _, n := range ns {
		sum += n
	}
	return sum
}

func max(ns ...int) int {
	max := ns[0]
	for i := 1; i < len(ns); i++ {
		if max < ns[i] {
			max = ns[i]
		}
	}
	return max
}

func min(ns ...int) int {
	min := ns[0]
	for i := 1; i < len(ns); i++ {
		if min > ns[i] {
			min = ns[i]
		}
	}
	return min
}

func pow(a, b int) int {
	ret := 1
	for b > 0 {
		if b&1 > 0 {
			ret = ret * a
		}
		a = a * a
		b >>= 1
	}
	return ret
}


package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"strconv"
)

var DEBUG = true

func main() {
	defer Flush()
	S := readb()
	X := make([][]byte, 2)
	d := 0

	Q := readi()
	for q := 0; q < Q; q++ {
		T := readi()
		if T == 1 {
			d = 1 - d
		} else {
			F := readi() - 1
			C := readb()[0]
			// 0, 0 -> f
			// 0, 1 -> r
			// 1, 0 -> r
			// 1, 1 -> f
			X[d^F] = append(X[d^F], C)
		}
	}

	rev(X[0])
	ans := X[0]
	ans = append(ans, S...)
	ans = append(ans, X[1]...)
	if d == 1 {
		rev(ans)
	}
	println(string(ans))
}

func rev(s []byte) {
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
		s[i], s[j] = s[j], s[i]
	}
}

// -----------------------------------------------------------------------------

// IO helper functions

// Returns next token from input.  It must be initialized by SetInput()
// before the first call.
var nextToken func() ([]byte, error)
var nextLine func() ([]byte, error)

// Holds a buffer for output.  It must be initialized by SetOutput().
// All IO fucntions (read*() and [e]print*()) should write to OutputWriter
// instead of this.
var OutputBuffer *bufio.Writer

// Holds an io.Writer.  It must be initialized by SetOutput()
var OutputWriter io.Writer

// Set IO functions for interactive input/output.
func SetInteractive(w io.Writer, r io.Reader) {
	SetUnbefferedInput(r)
	OutputBuffer = nil
	OutputWriter = w
}

// Setup OutputBuffer and OutputWriter.
func SetOutput(w io.Writer) {
	OutputBuffer = bufio.NewWriter(w)
	OutputWriter = OutputBuffer
}

// Flushes OutputBuffer
func Flush() {
	if OutputBuffer != nil {
		OutputBuffer.Flush()
	}
}

// Returns true if c is a white space
func IsSpace(c byte) bool {
	switch c {
	case '\t', '\n', '\v', '\f', '\r', ' ':
		return true
	}
	return false
}

func IsNewLine(c byte) bool {
	switch c {
	case '\n', '\r':
		return true
	}
	return false
}

// Setup nextToken with input buffer.
func SetInput(r io.Reader) {
	buf := new(bytes.Buffer)
	var b []byte

	var i int
	rest := func() ([]byte, error) {
		for i < len(b) && IsSpace(b[i]) {
			i++
		}
		if i == len(b) {
			return nil, io.ErrUnexpectedEOF
		}
		j := i
		for i < len(b) && !IsSpace(b[i]) {
			i++
		}
		return b[j:i], nil
	}
	initial := func() ([]byte, error) {
		io.Copy(buf, r)
		b = buf.Bytes()
		nextToken = rest
		return rest()
	}
	nextToken = initial

	restLn := func() ([]byte, error) {
		for i < len(b) && IsNewLine(b[i]) {
			i++
		}
		if i == len(b) {
			return nil, io.ErrUnexpectedEOF
		}
		j := i
		for i < len(b) && !IsNewLine(b[i]) {
			i++
		}
		return b[j:i], nil
	}

	initialLn := func() ([]byte, error) {
		io.Copy(buf, r)
		b = buf.Bytes()
		nextLine = restLn
		return restLn()
	}
	nextLine = initialLn
}

// Setup nextToken without input buffer.
func SetUnbefferedInput(r io.Reader) {
	buf := bufio.NewReader(r)
	var b []byte

	var i int
	nextToken = func() ([]byte, error) {
		var err error
		if i == len(b) {
			b, err = buf.ReadBytes('\n')
			if err != nil {
				return nil, err
			}
			i = 0
			j := len(b) - 1
			for 0 <= j && IsSpace(b[j]) {
				j--
			}
			b = b[0 : j+1]
		}
		for i < len(b) && IsSpace(b[i]) {
			i++
		}
		j := i
		for i < len(b) && !IsSpace(b[i]) {
			i++
		}
		if i == j {
			return nil, io.ErrUnexpectedEOF
		}
		return b[j:i], nil
	}
}

// -----------------------------------------------------------------------------

// IO functions

// Reads next token and return it as []byte
func readb() []byte {
	b, err := nextToken()
	if err != nil {
		panic(err)
	}
	return b[:len(b):len(b)]
}

// Reads next token and return it as string
func reads() string {
	return string(readb())
}

// Read next line as []byte.  Trailing '\n' will not be included.
// See also comments on readb()
func readbln() []byte {
	b, err := nextLine()
	if err != nil {
		panic(err)
	}
	return b[:len(b):len(b)]
}

// Read next line as string
func readsln() string {
	return string(readbln())
}

// Reads next token and return it as int64
func readll() int64 {
	i, err := strconv.ParseInt(reads(), 10, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// Reads next token and return it as int
func readi() int {
	return int(readll())
}

// Reads next token and return it as float64
func readf() float64 {
	f, err := strconv.ParseFloat(reads(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// Write args to OutputWriter with the format f
func printf(f string, args ...interface{}) (int, error) {
	return fmt.Fprintf(OutputWriter, f, args...)
}

// Write args to OutputWriter without format
func println(args ...interface{}) (int, error) {
	return fmt.Fprintln(OutputWriter, args...)
}

// Write args to stderr with the format f
func eprintf(f string, args ...interface{}) (int, error) {
	return fmt.Fprintf(os.Stderr, f, args...)
}

// Write args to stderr without format
func eprintln(args ...interface{}) (int, error) {
	return fmt.Fprintln(os.Stderr, args...)
}

func dbgf(f string, args ...interface{}) {
	if !DEBUG {
		return
	}
	fmt.Fprintf(os.Stderr, f, args...)
}

func dbg(args ...interface{}) {
	if !DEBUG {
		return
	}
	fmt.Fprintln(os.Stderr, args...)
}

// -----------------------------------------------------------------------------

// Utilities

func sumSlice(a []int) int {
	var res int
	for _, v := range a {
		res += v
	}
	return res
}

func sumSlicell(a []int64) int64 {
	var res int64
	for _, v := range a {
		res += v
	}
	return res
}

func readInts(N int) (int, []int) {
	if N == 0 {
		N = readi()
	}
	a := make([]int, N)
	for i := range a {
		a[i] = readi()
	}
	return N, a
}

func readIntsll(N int) (int, []int64) {
	if N == 0 {
		N = readi()
	}
	a := make([]int64, N)
	for i := range a {
		a[i] = readll()
	}
	return N, a
}

// reverse slice in place
func reverse(a []int) {
	for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
		a[i], a[j] = a[j], a[i]
	}
}

// areverse: allocating reverse
func areverse(a []int) []int {
	b := make([]int, len(a))
	for i := range a {
		b[i] = a[len(a)-i-1]
	}
	return b
}

// -----------------------------------------------------------------------------

// Simple math functions

const (
	// big prime
	INF  = 1000000007
	INF2 = 1000000009
	INF3 = 998244353
)

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func minll(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}

func minf(a, b float64) float64 {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a < b {
		return b
	}
	return a
}

func maxll(a, b int64) int64 {
	if a < b {
		return b
	}
	return a
}

func maxf(a, b float64) float64 {
	if a < b {
		return b
	}
	return a
}

func abs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}

func absll(a int64) int64 {
	if a < 0 {
		return -a
	}
	return a
}

func absf(a float64) float64 {
	if a < 0 {
		return -a
	}
	return a
}

// egcd(a, b) returns d, x, y:
//   d is gcd(a,b)
//   x, y are  integers that satisfy ax + by = d
func egcd(a, b int) (int, int, int) {
	if b == 0 {
		return a, 1, 0
	}
	d, x, y := egcd(b, a%b)
	return d, y, x - a/b*y
}

func egcdll(a, b int64) (int64, int64, int64) {
	if b == 0 {
		return a, 1, 0
	}
	d, x, y := egcdll(b, a%b)
	return d, y, x - a/b*y
}

func gcd(a, b int) int {
	d, _, _ := egcd(a, b)
	return d
}

func gcdll(a, b int64) int64 {
	d, _, _ := egcdll(a, b)
	return d
}

// set up IO functions
func init() {
	// for non-interactive
	SetInput(os.Stdin)
	SetOutput(os.Stdout)

	// Enable below when interactive.  Its ok to leave above intact.
	// SetInteractive(os.Stdout, os.Stdin)
}


package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"strconv"
)

func main() {
	defer Flush()

	S := readb()
	Q := readi()
	U := make([]byte, 0, Q)
	d := 0
	for q := 0; q < Q; q++ {
		T := readi()
		if T == 1 {
			d = 1 - d
		} else {
			F := readi() - 1
			C := readb()[0]
			// 0,0 -> f
			// 0,1 -> r
			// 1,0 -> r
			// 1,1 -> f

			if d^F == 0 {
				U = append(U, C)
			} else {
				S = append(S, C)
			}
		}
	}

	var ans []byte
	rev(U)
	ans = append(U, S...)
	if d != 0 {
		rev(ans)
	}
	println(string(ans))
}

func rev(a []byte) {
	for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
		a[i], a[j] = a[j], a[i]
	}
}

// -----------------------------------------------------------------------------

// IO helper functions

// Returns next token from input.  It must be initialized by SetInput()
// before the first call.
var nextToken func() ([]byte, error)
var nextLine func() ([]byte, error)

// Holds a buffer for output.  It must be initialized by SetOutput().
// All IO fucntions (read*() and [e]print*()) should write to OutputWriter
// instead of this.
var OutputBuffer *bufio.Writer

// Holds an io.Writer.  It must be initialized by SetOutput()
var OutputWriter io.Writer

// Set IO functions for interactive input/output.
func SetInteractive(w io.Writer, r io.Reader) {
	SetUnbefferedInput(r)
	OutputBuffer = nil
	OutputWriter = w
}

// Setup OutputBuffer and OutputWriter.
func SetOutput(w io.Writer) {
	OutputBuffer = bufio.NewWriter(w)
	OutputWriter = OutputBuffer
}

// Flushes OutputBuffer
func Flush() {
	if OutputBuffer != nil {
		OutputBuffer.Flush()
	}
}

// Returns true if c is a white space
func IsSpace(c byte) bool {
	switch c {
	case '\t', '\n', '\v', '\f', '\r', ' ':
		return true
	}
	return false
}

func IsNewLine(c byte) bool {
	switch c {
	case '\n', '\r':
		return true
	}
	return false
}

// Setup nextToken with input buffer.
func SetInput(r io.Reader) {
	buf := new(bytes.Buffer)
	var b []byte

	var i int
	rest := func() ([]byte, error) {
		for i < len(b) && IsSpace(b[i]) {
			i++
		}
		if i == len(b) {
			return nil, io.ErrUnexpectedEOF
		}
		j := i
		for i < len(b) && !IsSpace(b[i]) {
			i++
		}
		return b[j:i], nil
	}
	initial := func() ([]byte, error) {
		io.Copy(buf, r)
		b = buf.Bytes()
		nextToken = rest
		return rest()
	}
	nextToken = initial

	restLn := func() ([]byte, error) {
		for i < len(b) && IsNewLine(b[i]) {
			i++
		}
		if i == len(b) {
			return nil, io.ErrUnexpectedEOF
		}
		j := i
		for i < len(b) && !IsNewLine(b[i]) {
			i++
		}
		return b[j:i], nil
	}

	initialLn := func() ([]byte, error) {
		io.Copy(buf, r)
		b = buf.Bytes()
		nextLine = restLn
		return restLn()
	}
	nextLine = initialLn
}

// Setup nextToken without input buffer.
func SetUnbefferedInput(r io.Reader) {
	buf := bufio.NewReader(r)
	var b []byte

	var i int
	nextToken = func() ([]byte, error) {
		var err error
		if i == len(b) {
			b, err = buf.ReadBytes('\n')
			if err != nil {
				return nil, err
			}
			i = 0
			j := len(b) - 1
			for 0 <= j && IsSpace(b[j]) {
				j--
			}
			b = b[0 : j+1]
		}
		for i < len(b) && IsSpace(b[i]) {
			i++
		}
		j := i
		for i < len(b) && !IsSpace(b[i]) {
			i++
		}
		if i == j {
			return nil, io.ErrUnexpectedEOF
		}
		return b[j:i], nil
	}
}

// -----------------------------------------------------------------------------

// IO functions

// Reads next token and return it as []byte
func readb() []byte {
	b, err := nextToken()
	if err != nil {
		panic(err)
	}
	return b[:len(b):len(b)]
}

// Reads next token and return it as string
func reads() string {
	return string(readb())
}

// Read next line as []byte.  Trailing '\n' will not be included.
// See also comments on readb()
func readbln() []byte {
	b, err := nextLine()
	if err != nil {
		panic(err)
	}
	return b[:len(b):len(b)]
}

// Read next line as string
func readsln() string {
	return string(readbln())
}

// Reads next token and return it as int64
func readll() int64 {
	i, err := strconv.ParseInt(reads(), 10, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// Reads next token and return it as int
func readi() int {
	return int(readll())
}

// Reads next token and return it as float64
func readf() float64 {
	f, err := strconv.ParseFloat(reads(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// Write args to OutputWriter with the format f
func printf(f string, args ...interface{}) (int, error) {
	return fmt.Fprintf(OutputWriter, f, args...)
}

// Write args to OutputWriter without format
func println(args ...interface{}) (int, error) {
	return fmt.Fprintln(OutputWriter, args...)
}

// Write args to stderr with the format f
func eprintf(f string, args ...interface{}) (int, error) {
	return fmt.Fprintf(os.Stderr, f, args...)
}

// Write args to stderr without format
func eprintln(args ...interface{}) (int, error) {
	return fmt.Fprintln(os.Stderr, args...)
}

// -----------------------------------------------------------------------------

// Utilities

func sumSlice(a []int) int {
	var res int
	for _, v := range a {
		res += v
	}
	return res
}

func sumSlicell(a []int64) int64 {
	var res int64
	for _, v := range a {
		res += v
	}
	return res
}

func readInts(N int) (int, []int) {
	if N == 0 {
		N = readi()
	}
	a := make([]int, N)
	for i := range a {
		a[i] = readi()
	}
	return N, a
}

func readIntsll(N int) (int, []int64) {
	if N == 0 {
		N = readi()
	}
	a := make([]int64, N)
	for i := range a {
		a[i] = readll()
	}
	return N, a
}

// reverse slice in place
func reverse(a []int) {
	for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
		a[i], a[j] = a[j], a[i]
	}
}

// areverse: allocating reverse
func areverse(a []int) []int {
	b := make([]int, len(a))
	for i := range a {
		b[i] = a[len(a)-i-1]
	}
	return b
}

// -----------------------------------------------------------------------------

// Simple math functions

const (
	// big prime
	INF  = 1000000007
	INF2 = 1000000009
	INF3 = 998244353
)

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func minll(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}

func minf(a, b float64) float64 {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a < b {
		return b
	}
	return a
}

func maxll(a, b int64) int64 {
	if a < b {
		return b
	}
	return a
}

func maxf(a, b float64) float64 {
	if a < b {
		return b
	}
	return a
}

func abs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}

func absll(a int64) int64 {
	if a < 0 {
		return -a
	}
	return a
}

func absf(a float64) float64 {
	if a < 0 {
		return -a
	}
	return a
}

// egcd(a, b) returns d, x, y:
//   d is gcd(a,b)
//   x, y are  integers that satisfy ax + by = d
func egcd(a, b int) (int, int, int) {
	if b == 0 {
		return a, 1, 0
	}
	d, x, y := egcd(b, a%b)
	return d, y, x - a/b*y
}

func egcdll(a, b int64) (int64, int64, int64) {
	if b == 0 {
		return a, 1, 0
	}
	d, x, y := egcdll(b, a%b)
	return d, y, x - a/b*y
}

func gcd(a, b int) int {
	d, _, _ := egcd(a, b)
	return d
}

func gcdll(a, b int64) int64 {
	d, _, _ := egcdll(a, b)
	return d
}

// set up IO functions
func init() {
	// for non-interactive
	SetInput(os.Stdin)
	SetOutput(os.Stdout)

	// Enable below when interactive.  Its ok to leave above intact.
	// SetInteractive(os.Stdout, os.Stdin)
}


package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func reverseStr(s string) string {

	runes := []rune(s)

	for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
		runes[i], runes[j] = runes[j], runes[i]
	}

	return string(runes)
}

func nextInt() int {
	sc.Scan()
	i, e := strconv.Atoi(sc.Text())
	if e != nil {
		panic(e)
	}
	return i
}

func nextStr() string {
	sc.Scan()
	return sc.Text()
}

var sc = bufio.NewScanner(os.Stdin)

func main() {
	// Code for D - String Formation
	var S string
	fmt.Scan(&S)

	var Q int
	fmt.Scan(&Q)

	ans := make([]string, 0, Q)
	ans = append(ans, S)

	sc.Split(bufio.ScanWords)

	var T int
	var F int
	var C string
	var flag int
	for i := 0; i < Q; i++ {
		T = nextInt()
		if T == 1 {
			if flag == 0 {
				flag++
			} else {
				flag--
			}
		} else {
			F, C = nextInt(), nextStr()
			if (F == 1 && flag == 0) || (F == 2 && flag == 1) {
				temp := make([]string, 0)
				temp = append(temp, C)
				ans = append(temp, ans...)
			} else {
				ans = append(ans, C)
			}
		}
	}

	S = strings.Join(ans, "")

	if flag == 1 {
		S = reverseStr(S)
	}

	fmt.Println(S)

}


package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func reverseStr(s string) string {

	runes := []rune(s)

	for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
		runes[i], runes[j] = runes[j], runes[i]
	}

	return string(runes)
}

func nextInt() int {
	sc.Scan()
	i, e := strconv.Atoi(sc.Text())
	if e != nil {
		panic(e)
	}
	return i
}

func nextStr() string {
	sc.Scan()
	return sc.Text()
}

var sc = bufio.NewScanner(os.Stdin)

func main() {
	// Code for D - String Formation
	var S string
	fmt.Scan(&S)
	ans := make([]string, 0)
	ans = append(ans, S)

	var Q int
	fmt.Scan(&Q)

	sc.Split(bufio.ScanWords)

	var T int
	var F int
	var C string
	var flag int
	for i := 0; i < Q; i++ {
		T = nextInt()
		if T == 1 {
			if flag == 0 {
				flag++
			} else {
				flag--
			}
		} else {
			F, C = nextInt(), nextStr()
			if (F == 1 && flag == 0) || (F == 2 && flag == 1) {
				temp := make([]string, 0)
				temp = append(temp, C)
				ans = append(temp, ans...)
			} else {
				ans = append(ans, C)
			}
		}
	}

	S = strings.Join(ans, "")

	if flag == 1 {
		S = reverseStr(S)
	}

	fmt.Println(S)

}


package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func reverseStr(s string) string {

	runes := []rune(s)

	for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
		runes[i], runes[j] = runes[j], runes[i]
	}

	return string(runes)
}

func nextInt() int {
	sc.Scan()
	i, e := strconv.Atoi(sc.Text())
	if e != nil {
		panic(e)
	}
	return i
}

func nextStr() string {
	sc.Scan()
	return sc.Text()
}

var sc = bufio.NewScanner(os.Stdin)

func main() {
	// Code for D - String Formation
	var S string
	fmt.Scan(&S)

	var Q int
	fmt.Scan(&Q)

	sc.Split(bufio.ScanWords)

	var T int
	var F int
	var C string
	var flag int
	for i := 0; i < Q; i++ {
		T = nextInt()
		if T == 1 {
			if flag == 0 {
				flag++
			} else {
				flag--
			}
		} else {
			F, C = nextInt(), nextStr()
			if (F == 1 && flag == 0) || (F == 2 && flag == 1) {
				S = C + S
			} else {
				S += C
			}
		}
	}

	/*
		if flag == 1 {
			S = reverseStr(S)
		}
	*/
	fmt.Println(S)
}


s = gets.chomp
gets

head_tail, heading = ["", ""], 0

$<.each do |line|
  line.chomp!
  if line == "1"
    heading = 1 - heading
  elsif line[0,3] == "2 1"
    head_tail[heading] << line[-1]
  else
    head_tail[1-heading] << line[-1]
  end
end

s.reverse! unless heading.zero?
ans = head_tail[heading].reverse + s + head_tail[1-heading]
puts ans


S = gets.chomp
gets
HT,h = ['',''],0
$<.each{|ln| ln.chomp!
	if ln == '1'
		h = 1-h
	elsif ln[0,3] == '2 1'
		HT[h] << ln[-1]
	elsif ln[0,3] == '2 2'
		HT[1-h] << ln[-1]
	else end
}
print HT[h].reverse, (h==0 ? S : S.reverse), HT[1-h], "\n"


s = gets.to_s.chomp.bytes
q = gets.to_s.to_i

lr = [[], []]
state = 0

$<.each do |query|

  query.chomp!
  # p query
  if query == "1"
    state = 1 - state
    # s.reverse!
  else
    if query[0,3] == "2 1"
      lr[state] << query[-1].ord
    else
      lr[1-state] << query[-1].ord
    end
  end
end

if state == 1
  puts (lr[state].reverse + s.reverse + lr[1-state] ).pack("U*")
else
  puts (lr[state].reverse + s + lr[1-state] ).pack("U*")
end


s = gets.strip.split.map(&:to_s)
q = gets.to_i
q.times do
  a = gets.strip.split.map(&:to_s)
  if a.size == 1
    s.reverse!
  else
    if a[1]=="1"
      s.unshift(a[2])
    else
      s.push(a[2])
    end
  end
end
puts s.join("")


s=gets.chomp.split("").map(&:to_s)
q=gets.to_i

string=s

q.times.each do
    v=gets.chomp.split.map(&:to_s)
    v[0]=v[0].to_i
    v[1]=v[1].to_i
    if v[0]==1
        string=string.reverse
    elsif v[0]==2 && v[1]==1
        string.unshift(v[2].to_s)
    elsif v[0]==2 && v[1]==2
     string.push(v[2].to_s)
    end
   # p string
end

puts string.join("")


s = gets.chomp
q = gets.to_i

queries = []
q.times do
  query = gets.split
  if (size = query.size) == 1
    queries << query.map(&:to_i)
  else
    queries << query.map.with_index(1) { |string, i| i == size ? string : string.to_i }
  end
end

answer = [s]

reverse = false

queries.each do |query|
  if query.first == 1
    reverse = !reverse
  else
    if (query[1] == 1 && !reverse) || (query[1] == 2 && reverse)
      answer.unshift(query.last)
    else
      answer.push(query.last)
    end
  end
end

answer = answer.reverse if reverse

puts answer.join