There is a directed graph with N vertices and M edges. The i-th edge (1≤i≤M) points from vertex a_i to vertex b_i, and has a weight c_i. We will play the following single-player game using this graph and a piece.

Initially, the piece is placed at vertex 1, and the score of the player is set to 0. The player can move the piece as follows:

* When the piece is placed at vertex a_i, move the piece along the i-th edge to vertex b_i. After this move, the score of the player is increased by c_i.



The player can end the game only when the piece is placed at vertex N. The given graph guarantees that it is possible to traverse from vertex 1 to vertex N.

When the player acts optimally to maximize the score at the end of the game, what will the score be? If it is possible to increase the score indefinitely, print `inf`.

Constraints

* 2≤N≤1000
* 1≤M≤min(N(N-1),2000)
* 1≤a_i,b_i≤N (1≤i≤M)
* a_i≠b_i (1≤i≤M)
* a_i≠a_j or b_i≠b_j (1≤i<j≤M)
* -10^9≤c_i≤10^9 (1≤i≤M)
* c_i is an integer.
* In the given graph, there exists a path from vertex 1 to vertex N.

Input

Input is given from Standard Input in the following format:


N M
a_1 b_1 c_1
a_2 b_2 c_2
:
a_M b_M c_M


Output

Print the maximum possible score at the end of the game, if it is finite. If it is possible to increase the score indefinitely, print `inf`.

Examples

Input

3 3
1 2 4
2 3 3
1 3 5


Output

7


Input

2 2
1 2 1
2 1 1


Output

inf


Input

6 5
1 2 -1000000000
2 3 -1000000000
3 4 -1000000000
4 5 -1000000000
5 6 -1000000000


Output

-5000000000
/**
 * Created at 12:41 on 2019-08-12
 */

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

public class Main {

  static FastScanner sc = new FastScanner();
  static PrintStream out = System.out;
  static PrintWriter pw = new PrintWriter(out);

  static final int[] dx = {0, 1, 0, -1};
  static final int[] dy = {-1, 0, 1, 0};

  static final long MOD = (long) (1e9 + 7);
  static final long INF = Long.MAX_VALUE / 2;

  public static class Solver {
    public Solver() {

      int N = sc.nextInt();
      int M = sc.nextInt();

      BellmanFord2 bell = new BellmanFord2(N, M);

      long cost = -bell.shortestPath(0, N-1);

      out.println(cost == INF ? "inf" : cost);

    }


    public class BellmanFord2 extends Graph {

      static final long INF = Long.MAX_VALUE / 2;

      int N, M;

      public BellmanFord2(int N, int M) {
        this.N = N;
        this.M = M;
        read(N, M, true);
      }

      /*
        sからgまでの最小コストを返す
        sからgの間に負の閉路がある場合は-INFを返す
        そもそもたどり着けない場合はINFを返す
       */
      public long shortestPath(int s, int g) {

        boolean[] reachableToG = reachableTo(g);

        for (int i = 0; i < N; i++) {
          nodes[i].cost = INF;
        }

        nodes[s].cost = 0;

        LinkedList<Node> queue = new LinkedList<Node>();

        queue.add(nodes[s]);

        while(!queue.isEmpty()) {

          Node from = queue.pollFirst();

          if (!reachableToG[from.id]) continue;

          for (Edge e: from.edgesTo) {

            Node to = e.to();

            long newCost = from.cost + e.cost;

            if (newCost < e.to().cost) {
              to.cost = newCost;
              to.prev = from.id;
              queue.add(to);
              to.depth = Math.max(to.depth, from.depth+1);

              if (to.depth >= N) return -INF;
            }

          }

        }

        return nodes[g].cost;
      }

      public boolean hasNegativeCycle(int s, int g) {

        for (int i = 0; i < N; i++) {
          nodes[i].cost = 0;
        }

        boolean updated;

        for (int t = 0; t < N; t++) {
          updated = false;

          for (int i = 0; i < N; i++) {
            Node from = nodes[i];
            for (Edge e : nodes[i].edgesTo) {
              Node to = e.to();
              long newCost = from.cost + e.cost;
              if (newCost < to.cost) {
                to.cost = newCost;
                updated = true;

                if (i == N-1) return true;
              }
            }
          }

          if (!updated) break;
        }

        return false;
      }

    }


    public class Graph {

      public int oneBased = 1;

      static final long INF = Long.MAX_VALUE / 2;

      Node[] nodes;

      int V,E;

      /*
       * N: 頂点の数
       * M: 辺の数
       * hasCost: 辺にコストがあるか
       */
      public void read(int N, int M, boolean hasCost) {
        V = N;
        E = M;

        nodes = new Node[N];
        for (int i=0; i<N; i++) {
          nodes[i] = new Node(i, INF);
        }

        for (int i=0; i<M; i++) {
          int from = sc.nextInt()-oneBased;
          int to = sc.nextInt()-oneBased;
          long cost = -(hasCost ? sc.nextLong() : 1);
          Edge e = new Edge(from, to, cost);
          nodes[from].edgesTo.add(e);
          nodes[to].edgesFrom.add(e);
        }
      }

      public class Node {
        int id;
        long cost;
        int prev;
        int depth;
        LinkedList<Edge> edgesFrom = new LinkedList(); //このノードを終点とする辺
        LinkedList<Edge> edgesTo = new LinkedList(); //このノードを始点とする辺
        boolean done = false;

        public Node(int id, long cost) {
          this.id = id;
          this.cost = cost;
          prev = -1;
          depth = 0;
        }

        //木構造だった場合
        public Node parent() {
          return nodes[edgesFrom.get(0).to];
        }
      }

      public class Edge {
        int from, to;
        long cost;
        public Edge(int from, int to, long cost) {
          this.from = from;
          this.to = to;
          this.cost = cost;
        }
        public Node from() {
          return nodes[from];
        }
        public Node getFrom() {return from(); }
        public Node to() {
          return nodes[to];
        }
        public Node getTo() { return to(); }
      }

      public boolean[] reachableFrom(int s) {
        boolean[] visited = new boolean[V];

        LinkedList<Node> stack = new LinkedList<Node>();

        stack.add(nodes[s]);

        while(!stack.isEmpty()) {
          Node from = stack.getLast();
          visited[from.id] = true;
          for (Edge e: from.edgesTo) {
            if (!visited[e.to]) {
              stack.add(e.to());
            }
          }
        }

        return visited;
      }

      public boolean[] reachableTo(int g) {
        boolean[] visited = new boolean[V];

        LinkedList<Node> stack = new LinkedList<Node>();

        stack.add(nodes[g]);

        while(!stack.isEmpty()) {
          Node to = stack.removeLast();
          visited[to.id] = true;
          for (Edge e: to.edgesFrom) {
            if (!visited[e.from]) {
              stack.add(e.from());
            }
          }
        }

        return visited;
      }
    }


  }

  public static void main(String[] args) {
    new Solver();
  }

  static class FastScanner {
    private final InputStream in = System.in;
    private final byte[] buffer = new byte[1024];
    private int ptr = 0;
    private int buflen = 0;

    private boolean hasNextByte() {
      if (ptr < buflen) {
        return true;
      } else {
        ptr = 0;
        try {
          buflen = in.read(buffer);
        } catch (IOException e) {
          e.printStackTrace();
        }
        if (buflen <= 0) {
          return false;
        }
      }
      return true;
    }

    private int readByte() {
      if (hasNextByte()) return buffer[ptr++];
      else return -1;
    }

    private static boolean isPrintableChar(int c) {
      return 33 <= c && c <= 126;
    }

    private void skipUnprintable() {
      while (hasNextByte() && !isPrintableChar(buffer[ptr])) ptr++;
    }

    public boolean hasNext() {
      skipUnprintable();
      return hasNextByte();
    }

    public String next() {
      if (!hasNext()) throw new NoSuchElementException();
      StringBuilder sb = new StringBuilder();
      int b = readByte();
      while (isPrintableChar(b)) {
        sb.appendCodePoint(b);
        b = readByte();
      }
      return sb.toString();
    }

    public long nextLong() {
      if (!hasNext()) throw new NoSuchElementException();
      long n = 0;
      boolean minus = false;
      int b = readByte();
      if (b == '-') {
        minus = true;
        b = readByte();
      }
      if (b < '0' || '9' < b) {
        throw new NumberFormatException();
      }
      while (true) {
        if ('0' <= b && b <= '9') {
          n *= 10;
          n += b - '0';
        } else if (b == -1 || !isPrintableChar(b)) {
          return minus ? -n : n;
        } else {
          throw new NumberFormatException();
        }
        b = readByte();
      }
    }

    public int nextInt() {
      return (int) nextLong();
    }

    public int[] nextIntArray(int N, boolean oneBased) {
      if (oneBased) {
        int[] array = new int[N + 1];
        for (int i = 1; i <= N; i++) {
          array[i] = sc.nextInt();
        }
        return array;
      } else {
        int[] array = new int[N];
        for (int i = 0; i < N; i++) {
          array[i] = sc.nextInt();
        }
        return array;
      }
    }

    public long[] nextLongArray(int N, boolean oneBased) {
      if (oneBased) {
        long[] array = new long[N + 1];
        for (int i = 1; i <= N; i++) {
          array[i] = sc.nextLong();
        }
        return array;
      } else {
        long[] array = new long[N];
        for (int i = 0; i < N; i++) {
          array[i] = sc.nextLong();
        }
        return array;
      }
    }
  }

}
