#![allow(
    non_snake_case,
    unused_variables,
    unused_assignments,
    unused_mut,
    unused_imports,
    dead_code
)]
//use proconio::fastout;
use proconio::input;
use proconio::marker::*;
use std::cmp::*;
use std::collections::*;
use std::ops::Bound::Included;
//use std::collections::VecDeque;

const MOD: i64 = 1_000_000_007;
fn main() {
    input! {
       N:usize,M:usize,
       mut ABC:[(i64,i64,i64);N],
       mut DEF:[(i64,i64,i64);M]
    }
    let inf = std::i64::MAX / 2;
    //ABC.sort_by_key(|&(_, _, c)| c);
    //DEF.sort_by_key(|&(d, _, _)| d);
    // 壁の数は高々1000個なので、先に座標を圧縮する。
    let mut xmap = BTreeMap::new();
    let mut ymap = BTreeMap::new();
    xmap.insert(0, 0);
    ymap.insert(0, 0);
    for &(a, b, c) in ABC.iter() {
        xmap.insert(a, 0);
        xmap.insert(b, 0);
        ymap.insert(c, 0);
    }
    for &(d, e, f) in DEF.iter() {
        xmap.insert(d, 0);
        ymap.insert(e, 0);
        ymap.insert(f, 0);
    }
    let mut xmap_i = vec![0; xmap.len() * 2 + 1];
    let mut ymap_i = vec![0; ymap.len() * 2 + 1];
    for (i, (&k, _)) in xmap.clone().iter().enumerate() {
        xmap.insert(k, i * 2 + 1);
        xmap_i[i * 2 + 1] = k;
    }
    for (i, (&k, _)) in ymap.clone().iter().enumerate() {
        ymap.insert(k, i * 2 + 1);
        ymap_i[i * 2 + 1] = k;
    }
    let mut p = vec![vec![0; ymap.len() * 2 + 1]; xmap.len() * 2 + 1];
    for &(a, b, c) in ABC.iter() {
        let x1 = *xmap.get(&a).unwrap();
        let x2 = *xmap.get(&b).unwrap();
        let y = *ymap.get(&c).unwrap();
        for x in x1..=x2 {
            p[x][y] = 1;
        }
    }
    for &(d, e, f) in DEF.iter() {
        let x = *xmap.get(&d).unwrap();
        let y1 = *ymap.get(&e).unwrap();
        let y2 = *ymap.get(&f).unwrap();
        for y in y1..=y2 {
            p[x][y] = 1;
        }
    }
    // start位置を設定。
    // 移動候補をheapに追加していく。
    // println!("{:?}", p);
    let x = *xmap.get(&0).unwrap();
    let y = *ymap.get(&0).unwrap();
    let mut h = BinaryHeap::new();
    h.push((x - 1, y - 1));
    h.push((x - 1, y + 1));
    h.push((x + 1, y - 1));
    h.push((x + 1, y + 1));
    let mut ans = 0;
    //println!("xmap={:?},ymap={:?}", xmap, ymap);
    while h.len() > 0 {
        let (hx, hy) = h.pop().unwrap();
        if p[hx][hy] == 2 {
            continue;
        }
        if hx == 0 || hy == 0 || hx == xmap.len() * 2 || hy == ymap.len() * 2 {
            println!("INF");
            return;
        }
        //移動済みフラグ。
        p[hx][hy] = 2;
        // 領域の面積を加算。
        //println!("{:?}", h);
        //println!("{},{}", hx, hy);
        ans += (xmap_i[hx + 1] - xmap_i[hx - 1]) * (ymap_i[hy + 1] - ymap_i[hy - 1]) % MOD;
        //移動する方向に壁が無く、かつ移動先でもないなら、heapに積む。
        if p[hx - 1][hy] == 0 && p[hx - 2][hy] == 0 {
            h.push((hx - 2, hy));
        }
        if p[hx + 1][hy] == 0 && p[hx + 2][hy] == 0 {
            h.push((hx + 2, hy));
        }
        if p[hx][hy - 1] == 0 && p[hx][hy - 2] == 0 {
            h.push((hx, hy - 2));
        }
        if p[hx][hy + 1] == 0 && p[hx][hy + 2] == 0 {
            h.push((hx, hy + 2));
        }
    }
    //println!("{:?}", p);
    println!("{}", ans % MOD);
}
