Compare commits
24 Commits
nodejs
...
cd1261418a
Author | SHA1 | Date | |
---|---|---|---|
cd1261418a | |||
96abdd9852 | |||
22c85234da | |||
4bba4f9410 | |||
d928ad2ce3 | |||
63050a8065 | |||
0b08c1ce9c | |||
b7a8602e34 | |||
42eff5e0fa | |||
3d36c2704a | |||
ae036686b8 | |||
70f91c7586 | |||
913d53b757 | |||
8b68547644 | |||
0f85fcf021 | |||
1d4606db27 | |||
116bbe5218 | |||
1b52864952 | |||
92b70e632b | |||
c81937d6a5 | |||
f451850601 | |||
3bc6a56516 | |||
536af5f9c5 | |||
e5bdf2cc2c |
68
checkloc.php
Normal file
68
checkloc.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
// FUNCTION TO CALCULATE HAVERSINE DISTANCE GIVEN COORDINATES OF
|
||||
// TWO POINTS, AND RADIUS (IN KM)
|
||||
function haversine_distance($lat1, $long1, $lat2, $long2, $radius) {
|
||||
$term_1 = $lat2 - $lat1;
|
||||
$term_1 = $term_1 / 2;
|
||||
$term_1 = sin($term_1);
|
||||
$term_1 = pow($term_1, 2);
|
||||
|
||||
$term_2 = $long2 - $long1;
|
||||
$term_2 = $term_2 / 2;
|
||||
$term_2 = sin($term_2);
|
||||
$term_2 = pow($term_2, 2);
|
||||
$term_2 = $term_2 * cos($lat1);
|
||||
$term_2 = $term_2 * cos($lat2);
|
||||
|
||||
$distance = $term_1 + $term_2;
|
||||
$distance = sqrt($distance);
|
||||
$distance = asin($distance);
|
||||
$distance = $distance * 2;
|
||||
$distance = $distance * $radius;
|
||||
|
||||
return $distance;
|
||||
}
|
||||
|
||||
|
||||
function km_to_miles($distance) {
|
||||
return $distance * 0.62137119;
|
||||
}
|
||||
|
||||
|
||||
$user_lat = $_GET["latitude"];
|
||||
$user_lat = $user_lat * (M_PI / 180);
|
||||
$user_long = $_GET["longitude"];
|
||||
$user_long = $user_long * (M_PI / 180);
|
||||
$glink = $_GET["glink"];
|
||||
|
||||
$cluster = Cassandra::cluster()->withPersistentSessions(true)->build();
|
||||
$keyspace = 'glink';
|
||||
$session = $cluster->connect($keyspace);
|
||||
$statement = $session->prepare('SELECT latitude,longitude,radius,url FROM data WHERE shortlink=? ALLOW FILTERING;');
|
||||
$result = $session->execute($statement,array('arguments' => array($glink)));
|
||||
|
||||
$link_lat = floatval($result[0]['latitude']);
|
||||
$link_lat = $link_lat * (M_PI / 180);
|
||||
$link_long = floatval($result[0]['longitude']);
|
||||
$link_long = $link_long * (M_PI / 180);
|
||||
$target_radius = intval($result[0]['radius']);
|
||||
|
||||
$url = $result[0]['url'];
|
||||
|
||||
$distance = haversine_distance($link_lat, $link_long, $user_lat, $user_long, 6371.009);
|
||||
$distance = km_to_miles($distance);
|
||||
|
||||
if ($distance <= $target_radius) {
|
||||
printf("%s",$url);
|
||||
} else {
|
||||
printf("B");
|
||||
}
|
||||
|
||||
// Check the database to see if user is allowed to access the URL. If they are, respond 'Yes' (for the time being), if they are not, respond 'No' (for the time being).
|
||||
|
||||
// To check if the user is allowed to access the URL, check if the distance between their location and the location in the database is less than the radius. To compute the
|
||||
// distance, use something like Haversine Forumla.
|
||||
|
||||
|
||||
?>
|
23
index.html
23
index.html
@@ -7,17 +7,34 @@
|
||||
<body>
|
||||
<div id="root">
|
||||
<h1>Link Shortener</h1>
|
||||
<form id="form" action="result.js">
|
||||
<form id="form" method="GET" action="result.php" onsubmit="return validate()">
|
||||
|
||||
<!-- <form id="form"> -->
|
||||
<label for="url">URL:</label><span class="mandatory">*</span>
|
||||
<input type="text" name="url" id="URL" value="example.com" required><br><br>
|
||||
<input type="text" name="url" id="URL" value="https://example.com" required><br><br>
|
||||
|
||||
<label for="labels">GLink:</label><span class="mandatory">*</span>
|
||||
<label for="GLink" id="labels" class="glink">glink.zip/</label><input type="text" name="glink" id="GLink" class="glink" value="exampleWebsite" required>
|
||||
<label for="GLink" id="labels" class="glink">glink.zip/</label><input type="text" name="glink" id="GLink" class="glink" value="exampleWebsite">
|
||||
|
||||
<span role="alert" id="error" aria-hidden="true">Invalid URL</span>
|
||||
|
||||
<br><br>
|
||||
<label for="restricted">Geo-restricted?: </label> <input type="checkbox" name="restricted" id="restricted"> <span id="loadingText" style="position: relative; left: 20px;"></span>
|
||||
<br><br>
|
||||
<label for="radius" hidden="hidden" id="radius_label">Radius: </label> <span id="mandatory-radius" class="mandatory" hidden="hidden">*</span>
|
||||
<select name="radius" id="radius" hidden="hidden">
|
||||
<option value="" selected disabled hidden>Select a radius</option>
|
||||
<option value="5">5 mi</option>
|
||||
<option value="10">10 mi</option>
|
||||
<option value="15">15 mi</option>
|
||||
<option value="20">20 mi</option>
|
||||
</select>
|
||||
<br><br>
|
||||
<input type="submit" id="button" value="Zip It!">
|
||||
|
||||
|
||||
<input type="hidden" name="latitude" id="latitude">
|
||||
<input type="hidden" name="longitude" id="longitude">
|
||||
</form>
|
||||
<hr>
|
||||
<div>
|
||||
|
230
index.js
230
index.js
@@ -1,67 +1,175 @@
|
||||
const submit = document.getElementById("button");
|
||||
submit.addEventListener('click', validate);
|
||||
function validate(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const url = document.getElementById("URL");
|
||||
const glink = document.getElementById("GLink");
|
||||
// if (!url) {
|
||||
// /* Flag */
|
||||
// }
|
||||
let valid = true;
|
||||
const domainExp = new RegExp("http(s)*:\\/\\/[a-zA-Z0-9\\-]+(\\.[a-zA-Z0-9\\-]+)+");
|
||||
const filepathExp = new RegExp("[a-zA-Z]+");
|
||||
let count = 0;
|
||||
let index = -1;
|
||||
let domain = "";
|
||||
let filepath = "";
|
||||
for (let i=0; i < url.value.length; i++) {
|
||||
if (url.value.charAt(i) == '/') {
|
||||
count++;
|
||||
}
|
||||
if (count == 3) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
// const submit = document.getElementById("button");
|
||||
mycheckbox = document.getElementById("restricted");
|
||||
mycheckbox.addEventListener('change',checkboxCallback);
|
||||
window.onload = function() {
|
||||
if (mycheckbox.checked) {
|
||||
document.getElementById("radius_label").hidden = false;
|
||||
document.getElementById("mandatory-radius").hidden = false;
|
||||
var radiusSelect = document.getElementById("radius");
|
||||
radiusSelect.hidden = false;
|
||||
radiusSelect.required = true;
|
||||
}
|
||||
if (count >= 3) {
|
||||
domain = url.value.substring(0, index);
|
||||
if (index == url.value.length - 1) {
|
||||
filepath = url.value.charAt(index);
|
||||
}
|
||||
|
||||
var lat = document.getElementById("latitude");
|
||||
lat.setValue = function(newValue) {
|
||||
this.value = newValue;
|
||||
valueReceived();
|
||||
}
|
||||
|
||||
function valueReceived() {
|
||||
let load = document.getElementById("loadingText");
|
||||
load.innerHTML = "Location retrieved";
|
||||
load.style.color = "green";
|
||||
|
||||
}
|
||||
function valueRequested() {
|
||||
let load = document.getElementById("loadingText");
|
||||
load.innerHTML = "Location requested. Please wait...";
|
||||
load.style.color = "red";
|
||||
|
||||
}
|
||||
function checkboxCallback(event) {
|
||||
const radiusLabel = document.getElementById("radius_label");
|
||||
const radiusSelect = document.getElementById("radius");
|
||||
const mandatoryRadius = document.getElementById("mandatory-radius");
|
||||
if (event.currentTarget.checked) {
|
||||
radiusLabel.hidden = false;
|
||||
mandatoryRadius.hidden = false;
|
||||
radiusSelect.hidden = false;
|
||||
radiusSelect.required = true;
|
||||
valueRequested();
|
||||
getLocation();
|
||||
} else {
|
||||
radiusLabel.hidden = true;
|
||||
mandatoryRadius.hidden = true;
|
||||
radiusSelect.hidden = true;
|
||||
radiusSelect.required = false;
|
||||
}
|
||||
}
|
||||
|
||||
function getLocation() {
|
||||
console.log("GeoLocation");
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(showPosition);
|
||||
} else {
|
||||
console.log("Your browser does not support geolocation.");
|
||||
}
|
||||
}
|
||||
|
||||
function showPosition(position) {
|
||||
console.log("Gotten positions");
|
||||
console.log(position.coords.latitude);
|
||||
console.log(position.coords.longitude);
|
||||
|
||||
document.getElementById("latitude").setValue(position.coords.latitude);
|
||||
document.getElementById("longitude").value = position.coords.longitude;
|
||||
console.log("done");
|
||||
}
|
||||
|
||||
// submit.addEventListener('click', validate);
|
||||
function validate() {
|
||||
//e.preventDefault();
|
||||
const checked = document.getElementById("restricted");
|
||||
if (checked.checked) {
|
||||
const lat = document.getElementById("latitude");
|
||||
const long = document.getElementById("longitude");
|
||||
if (lat.value === "" || long.value === "") {
|
||||
/* wait */
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const url = document.getElementById("URL");
|
||||
let glink = document.getElementById("GLink");
|
||||
const error = document.getElementById("error");
|
||||
// if (!url) {
|
||||
// /* Flag */
|
||||
// }
|
||||
let valid = true;
|
||||
const domainExp = new RegExp("^http(s)*:\\/\\/[a-zA-Z0-9\\-]+(\\.[a-zA-Z0-9\\-]+)+$");
|
||||
const filepathExp = new RegExp("^[a-zA-Z]+$");
|
||||
const glinkExp = new RegExp("^[a-zA-Z]*$");
|
||||
let glinkStr = glink.value;
|
||||
let count = 0;
|
||||
let index = -1;
|
||||
let domain = "";
|
||||
let filepath = "";
|
||||
for (let i = 0; i < url.value.length; i++) {
|
||||
if (url.value.charAt(i) == '/') {
|
||||
count++;
|
||||
}
|
||||
if (count == 3) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count >= 3) {
|
||||
domain = url.value.substring(0, index);
|
||||
if (index == url.value.length - 1) {
|
||||
filepath = url.value.charAt(index);
|
||||
} else {
|
||||
filepath = url.value.substring(index, url.value.length - 1);
|
||||
}
|
||||
alert("Domain is " + domain + " filepath is " + filepath);
|
||||
} else {
|
||||
filepath = url.value.substring(index, url.value.length - 1);
|
||||
domain = url.value;
|
||||
}
|
||||
alert("Domain is " + domain + " filepath is " + filepath);
|
||||
} else {
|
||||
domain = url.value;
|
||||
}
|
||||
console.log(domain);
|
||||
if (domain.match(domainExp)) /** and is available? */{
|
||||
const error = document.getElementById("error");
|
||||
if (error.classList.contains("visible")) {
|
||||
error.classList.remove("visible");
|
||||
}
|
||||
if (url.classList.contains("invalid")) {
|
||||
url.classList.remove("invalid");
|
||||
}
|
||||
url.classList.add("valid");
|
||||
error.setAttribute('aria-hidden', true);
|
||||
error.setAttribute('aria-invalid', false);
|
||||
console.log("Valid");
|
||||
return valid;
|
||||
} else {
|
||||
console.log(domain);
|
||||
|
||||
/*flag*/
|
||||
const error = document.getElementById("error");
|
||||
error.classList.add("visible");
|
||||
|
||||
//error.classList.add("hidden");
|
||||
if (url.classList.contains("valid")) {
|
||||
url.classList.remove("valid");
|
||||
if (glinkStr === "") {
|
||||
var result = window.confirm("You have left the glink field blank. A random one will be generated for you.");
|
||||
if (result === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
url.classList.add("invalid");
|
||||
error.setAttribute('aria-hidden', false);
|
||||
error.setAttribute('aria-invalid', true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (domain.match(domainExp) && glinkStr.match(glinkExp))/** and is available? */{
|
||||
if (error.classList.contains("visible")) {
|
||||
error.classList.remove("visible");
|
||||
}
|
||||
if (url.classList.contains("invalid")) {
|
||||
url.classList.remove("invalid");
|
||||
}
|
||||
url.classList.add("valid");
|
||||
if (glink.classList.contains("invalid")) {
|
||||
glink.classList.remove("invalid");
|
||||
}
|
||||
glink.classList.add("valid");
|
||||
error.setAttribute('aria-hidden', true);
|
||||
error.setAttribute('aria-invalid', false);
|
||||
console.log("Valid with url= " +url.value+ " glink=" +glink);
|
||||
return valid;
|
||||
} else {
|
||||
/*flag*/
|
||||
error.classList.add("visible");
|
||||
|
||||
//error.classList.add("hidden");
|
||||
if (!domain.match(domainExp)) {
|
||||
if (url.classList.contains("valid")) {
|
||||
url.classList.remove("valid");
|
||||
}
|
||||
url.classList.add("invalid");
|
||||
} else {
|
||||
if (url.classList.contains("invalid")) {
|
||||
url.classList.remove("invalid");
|
||||
}
|
||||
url.classList.add("valid");
|
||||
}
|
||||
if (!glinkStr.match(glinkExp)) {
|
||||
if (glink.classList.contains("valid")) {
|
||||
glink.classList.remove("valid");
|
||||
}
|
||||
glink.classList.add("invalid");
|
||||
} else {
|
||||
if (glink.classList.contains("invalid")) {
|
||||
glink.classList.remove("invalid");
|
||||
}
|
||||
glink.classList.add("valid");
|
||||
}
|
||||
error.setAttribute('aria-hidden', false);
|
||||
error.setAttribute('aria-invalid', true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
42
redirect.php
Normal file
42
redirect.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
use Cassandra;
|
||||
|
||||
$uri = $_SERVER['REQUEST_URI'];
|
||||
$uri = substr($uri,1);
|
||||
|
||||
$matches_uri = preg_match('/^[a-zA-Z]+$/',$uri);
|
||||
|
||||
if (($matches_uri == 0) || ($matches_uri == false)) {
|
||||
header("Location: http://glink.zip/");
|
||||
exit;
|
||||
} else {
|
||||
|
||||
$cluster = Cassandra::cluster()->withPersistentSessions(true)->build();
|
||||
$keyspace = 'glink';
|
||||
$session = $cluster->connect($keyspace);
|
||||
|
||||
$statement = $session->prepare('SELECT url,is_geo FROM data WHERE shortlink=? ALLOW FILTERING;');
|
||||
$result = $session->execute($statement,array('arguments' => array($uri)));
|
||||
|
||||
if ($result->count() == 0) {
|
||||
printf('The given GLink was invalid, and doesn\'t point to a specific web page.');
|
||||
exit;
|
||||
}
|
||||
|
||||
foreach($result as $row) {
|
||||
if (is_null($row)) {
|
||||
printf('The given GLink was invalid, and doesn\'t point to a specific web page.');
|
||||
exit;
|
||||
} else {
|
||||
if ($row['is_geo'] == true) {
|
||||
header("Location: https://glink.zip/reqloc.html?glink=" . $uri);
|
||||
exit;
|
||||
} else {
|
||||
header("Location: " . $row['url']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
59
reqloc.html
Normal file
59
reqloc.html
Normal file
@@ -0,0 +1,59 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Location needed</title>
|
||||
</head>
|
||||
<body onload="get_location()">
|
||||
This link is geo-restricted. Your location is needed to verify that you are authorized to access this link.
|
||||
|
||||
<script>
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
var glink = params.get("glink");
|
||||
|
||||
var lat;
|
||||
var long;
|
||||
var method = "GET";
|
||||
var request;
|
||||
|
||||
function requestHandler() {
|
||||
if (request.readyState === XMLHttpRequest.DONE) {
|
||||
if (request.status === 200) {
|
||||
if (request.responseText == "B") {
|
||||
alert("You are not authorized to access this GLink, as you are outside the permitted radius. If you think this is an error, please try again on a mobile device.");
|
||||
} else {
|
||||
window.location.replace(request.responseText);
|
||||
}
|
||||
} else {
|
||||
console.log("Error sending data to server.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function storeLocation(position) {
|
||||
lat = position.coords.latitude;
|
||||
long = position.coords.longitude;
|
||||
}
|
||||
|
||||
function callbackFunction(position) {
|
||||
storeLocation(position);
|
||||
request = new XMLHttpRequest();
|
||||
request.onreadystatechange = requestHandler;
|
||||
if (method == "GET") {
|
||||
request.open("GET","/checkloc.php?latitude=" + encodeURIComponent(lat) + "&longitude=" + encodeURIComponent(long) + "&glink=" + encodeURIComponent(glink));
|
||||
request.send();
|
||||
} else if (method == "POST") {
|
||||
request.open("POST","/checkloc.php");
|
||||
request.send("latitude=" + encodeURIComponent(lat) + "&longitude=" + encodeURIComponent(long));
|
||||
}
|
||||
}
|
||||
|
||||
function get_location() {
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(callbackFunction);
|
||||
|
||||
} else {
|
||||
alert('You cannot access this GLink as your browser does not support geolocation.');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -1,8 +0,0 @@
|
||||
const cassandra = require('cassandra-driver');
|
||||
|
||||
const client = new cassandra.Client({
|
||||
contactPoints: ['127.0.0.1:9042'],
|
||||
keyspace: 'glink',
|
||||
});
|
||||
|
||||
const query =
|
120
result.php
Normal file
120
result.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
function gen_base62_rand_shortlink($len) {
|
||||
$rand_bytes = random_bytes(intval(($len * 2) / 3));
|
||||
$rand_string = base64_encode($rand_bytes);
|
||||
$rand_string = str_replace("+","",$rand_string);
|
||||
$rand_string = str_replace("/","",$rand_string);
|
||||
$rand_string = str_replace("=","",$rand_string);
|
||||
|
||||
if (mb_strlen($rand_string) < $len) {
|
||||
$curlen = mb_strlen($rand_string);
|
||||
$rand_string = $rand_string . gen_rand_shortlink($len - $curlen);
|
||||
}
|
||||
|
||||
return $rand_string;
|
||||
}
|
||||
|
||||
function gen_rand_shortlink($len) {
|
||||
$to_return = '';
|
||||
$possible_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
while (mb_strlen($to_return) < $len) {
|
||||
$to_return = $to_return . $possible_chars[rand(0, mb_strlen($possible_chars)-1)];
|
||||
}
|
||||
|
||||
return $to_return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
$cluster = Cassandra::cluster()->withPersistentSessions(true)->build();
|
||||
$keyspace = 'glink';
|
||||
$session = $cluster->connect($keyspace);
|
||||
|
||||
$url = $_GET["url"];
|
||||
|
||||
if (isset($_GET["restricted"])) {
|
||||
$is_geo = 1;
|
||||
} else {
|
||||
$is_geo = 0;
|
||||
}
|
||||
|
||||
if ($is_geo == 1) {
|
||||
$radius = $_GET["radius"];
|
||||
|
||||
$latitude = $_GET["latitude"];
|
||||
$latitude = doubleval($latitude);
|
||||
|
||||
$longitude = $_GET["longitude"];
|
||||
$longitude = doubleval($longitude);
|
||||
}
|
||||
|
||||
$matches = preg_match('/^http(s)*:\\/\\/[a-zA-Z0-9\\-]+(\\.[a-zA-Z0-9\\-]+)+$/',$url);
|
||||
if (($matches == 0) || ($matches == false)) {
|
||||
printf("The URL entered was invalid. Please try again.");
|
||||
return;
|
||||
}
|
||||
|
||||
$shortlink = $_GET["glink"];
|
||||
|
||||
if ($shortlink != '') {
|
||||
$matches_shortlink = preg_match('/^[a-zA-Z]+$/',$shortlink);
|
||||
if (($matches_shortlink == 0) || ($matches_shortlink == false)) {
|
||||
printf("The GLink entered was invalid. The GLink can only contain letters. Please try again.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* generate a random shortlink */
|
||||
gen_shortlink:
|
||||
$rand_string = gen_rand_shortlink(6); /* the function is defined at the start of this file */
|
||||
$shortlink = $rand_string;
|
||||
|
||||
/* Check if shortlink is already taken by querying the database */
|
||||
$statement = $session->prepare('SELECT url FROM data WHERE shortlink=? ALLOW FILTERING');
|
||||
$result = $session->execute($statement,array('arguments' => array($shortlink)));
|
||||
|
||||
if ($result->count() != 0) {
|
||||
goto gen_shortlink;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//$statement = new Cassandra\SimpleStatement('SELECT name FROM data WHERE id=5');
|
||||
|
||||
$statement = $session->prepare('SELECT url FROM data WHERE shortlink=? ALLOW FILTERING');
|
||||
$options = array('arguments' => array($shortlink));
|
||||
$result = $session->execute($statement,$options);
|
||||
|
||||
if ($result->count() != 0) {
|
||||
printf('That GLink is already taken. Please try another one.');
|
||||
exit;
|
||||
}
|
||||
|
||||
$rand_num = rand(0,99999999);
|
||||
|
||||
$statement = $session->prepare('INSERT INTO data (id, url, shortlink, is_geo, radius, latitude, longitude, when_created) VALUES (?,?,?,?,?,?,?,toTimestamp(now())) USING TTL 20');
|
||||
|
||||
if ($is_geo == 1) {
|
||||
$options = array($rand_num,$url,$shortlink,boolval($is_geo),intval($radius), $latitude, $longitude);
|
||||
} else {
|
||||
$options = array($rand_num,$url,$shortlink,boolval($is_geo),null,null,null);
|
||||
}
|
||||
|
||||
$result = $session->execute($statement,array('arguments' => $options));
|
||||
|
||||
//$stringRepresentation= json_encode($result[0]);
|
||||
|
||||
//printf("%s\n\n\n",$stringRepresentation);
|
||||
|
||||
//foreach($result as $row) {
|
||||
// if (is_null($row)) {
|
||||
// printf('Unsuccessful');
|
||||
// } else {
|
||||
printf('Successful: The URL you entered was: %s and your GLink is: https://glink.zip/%s', $url,$shortlink);
|
||||
// }
|
||||
//}
|
||||
//printf('Done');
|
||||
|
||||
?>
|
Reference in New Issue
Block a user