/*
    一个图
    每条边上有两个值(gcd,lcm) 其值是该边两个顶点u,v上值的gcd和lcm
    现给出一些边,问有没存在顶点的值满足边的限制
    n <= 100 , m <= n(n-1)/2
    1 <= gcd , lcm <= 10^6

    由于gcd , lcm比较小
    选取任意一个顶点,枚举它的值val,val要满足val % gcd == 0 , lcm % val == 0
    for( val = gcd ; val <= lcm ; val += gcd)
        if( lcm % val == 0)
            检查
    由lcm = a * b / gcd ,知道了a就推出b了
    所以由选取的那个点出发,去推出其他点的值,若之前已经推出了,判断其是否矛盾
*/

#include
<iostream>
#include
<cstring>
#include
<map>
#include
<algorithm>
#include
<stack>
#include
<queue>
#include
<cmath>
#include
<string>
#include
<cstdlib>
#include
<vector>
#include
<cstdio>
#include
<set>
#include
<list>

using namespace std;

struct Edge{
    
int v , l , g;
    Edge(
int v , int g , int l): v(v), g(g), l(l){
    }

}
;

vector
<Edge> E[101];
int ans[101];
stack
<int> s;

int gcd(int a , int b){
    
return b == 0 ? a : gcd(b , a % b);
}


int lcm(int a ,int b){
    
return a / gcd(a,b) * b;
}



bool chk(int u){
    s.push(u);
    
for(vector<Edge>::iterator it = E[u].begin() ; it != E[u].end() ; it++){
        
int v = it->v , g = it->g , l = it->l;
        
if(l % ans[u] != 0 || ans[u] % g != 0){
            
return false;
        }

        
if(ans[v] != -1){
            
if(gcd(ans[u], ans[v]) != g || lcm(ans[u], ans[v]) != l){
                
return false;
            }

        }
else{
            ans[v] 
= l / ans[u] * g ;
            
if(!chk(v)){
                
return false;
            }

        }

    }

    
return true;
}


bool gao(int u){
    
if(E[u].empty()){
        ans[u] 
= 1;
        
return true;
    }

    
while(!s.empty()){//don't forget !!!
        s.pop();
    }

    Edge e 
= E[u][0];
    
int g = e.g , l = e.l;
    
for(int val = g ; val <= l ; val += g){
        
if(l % val !=0){
            
continue;
        }
        
        ans[u] 
= val;
        
if(chk(u)){
            
return true;
        }
else{
            
while(!s.empty()){
                ans[s.top()] 
= -1;
                s.pop();
            }

        }

    }

    
return false;
}


int main()
{
    
for(int n, m; ~scanf("%d%d",&n, &m); ){
        
for(int i = 1 ; i <= n ; i ++){
            E[i].clear();
        }

        
bool err = false;
        
for(int i = 0 ; i < m ; i ++){
            
int u, v, g, l;
            scanf(
"%d%d%d%d",&u,&v,&g,&l);
            E[u].push_back(Edge(v, g, l));
            E[v].push_back(Edge(u, g, l));
            
if(l % g != 0){
                err 
= true;
            }

        }


        
if(!err){
            fill(ans
+1,ans+1+n,-1);
            
for(int u = 1 ; u <= n; u++){
                
if(ans[u] == -1){
                    
if(!gao(u)){
                        err 
= true;
                        
break;
                    }

                }

            }

        }


        
if(err){
            puts(
"NO");
        }
else{
            puts(
"YES");
            
for(int i = 1 ; i <= n ; i++){
                
if(i>1){
                    putchar(
' ');
                }

                printf(
"%d",ans[i]);
            }

            puts(
"");
        }

    }
    
    
return 0;
}