Tambahkan akhiran st, nd, rd dan th (ordinal) ke sebuah angka

150

Saya ingin menghasilkan string teks secara dinamis berdasarkan hari ini. Jadi, misalnya, jika ini adalah hari 1 maka saya ingin kode saya menghasilkan = "Ini adalah <dynamic> 1 * <string dinamis> st </ string dinamis> * </dynamic>".

Ada total 12 hari jadi saya telah melakukan yang berikut:

  1. Saya telah membuat loop for yang loop selama 12 hari.

  2. Di html saya, saya telah memberikan elemen saya id unik untuk menargetkannya, lihat di bawah:

    <h1 id="dynamicTitle" class="CustomFont leftHeading shadow">On The <span></span> <em>of rest of generic text</em></h1>
  3. Kemudian, di dalam for for loop saya memiliki kode berikut:

    $("#dynamicTitle span").html(i);
    var day = i;
    if (day == 1) {
        day = i + "st";
    } else if (day == 2) {
        day = i + "nd"
    } else if (day == 3) {
        day = i + "rd"
    }
    

MEMPERBARUI

Ini adalah keseluruhan untuk loop seperti yang diminta:

$(document).ready(function () {
    for (i = 1; i <= 12; i++) {
        var classy = "";
        if (daysTilDate(i + 19) > 0) {
            classy = "future";
            $("#Day" + i).addClass(classy);
            $("#mainHeading").html("");
            $("#title").html("");
            $("#description").html("");
        } else if (daysTilDate(i + 19) < 0) {
            classy = "past";
            $("#Day" + i).addClass(classy);
            $("#title").html("");
            $("#description").html("");
            $("#mainHeading").html("");
            $(".cta").css('display', 'none');
            $("#Day" + i + " .prizeLink").attr("href", "" + i + ".html");
        } else {
            classy = "current";
            $("#Day" + i).addClass(classy);
            $("#title").html(headings[i - 1]);
            $("#description").html(descriptions[i - 1]);
            $(".cta").css('display', 'block');
            $("#dynamicImage").attr("src", ".." + i + ".jpg");
            $("#mainHeading").html("");
            $(".claimPrize").attr("href", "" + i + ".html");
            $("#dynamicTitle span").html(i);
            var day = i;
            if (day == 1) {
                day = i + "st";
            } else if (day == 2) {
                day = i + "nd"
            } else if (day == 3) {
                day = i + "rd"
            } else if (day) {
            }
        }
    }
Antonio Vasilev
sumber
1
Jika kode sumber Anda cukup pendek, bisakah Anda memposting hal yang lengkap, dan juga mengatakan dengan tepat apa yang salah atau apa yang membingungkan Anda?
RonaldBarzell
Apa yang kode Anda lakukan / tidak lakukan saat ini? Anda tidak dengan jelas menyatakan apa yang salah.
Runcing
Saya menduga kode yang ditampilkan adalah isi dari ifblok yang selanjutnya dikandung oleh loop? Tampilkan lebih banyak kode ....
MrCode
@ Kode Kode - Ya, Anda benar. Saya telah memperbarui pos untuk menyertakan keseluruhan untuk loop. Saya harap ini jelas!
Antonio Vasilev
rapi dan bekerja dengan baik.
Dan Jay

Jawaban:

345

The Aturan adalah sebagai berikut:

  • st digunakan dengan angka yang diakhiri dengan 1 (mis. 1, diucapkan lebih dulu)
  • nd digunakan dengan angka yang diakhiri dengan 2 (misalnya 92, diucapkan sembilan puluh detik)
  • rd digunakan dengan angka yang berakhiran 3 (mis. 33, diucapkan tigapuluh tiga)
  • Sebagai pengecualian dari aturan di atas, semua angka "remaja" yang diakhiri dengan penggunaan 11, 12 atau 13 (mis. 11, diucapkan kesebelas, 112, diucapkan seratus [dan] kedua belas)
  • th digunakan untuk semua nomor lainnya (misalnya nomor 9, diucapkan kesembilan).

Kode JavaScript berikut (ditulis ulang pada Juni '14) menyelesaikan ini:

function ordinal_suffix_of(i) {
    var j = i % 10,
        k = i % 100;
    if (j == 1 && k != 11) {
        return i + "st";
    }
    if (j == 2 && k != 12) {
        return i + "nd";
    }
    if (j == 3 && k != 13) {
        return i + "rd";
    }
    return i + "th";
}

Contoh output untuk angka antara 0-115:

  0  0th
  1  1st
  2  2nd
  3  3rd
  4  4th
  5  5th
  6  6th
  7  7th
  8  8th
  9  9th
 10  10th
 11  11th
 12  12th
 13  13th
 14  14th
 15  15th
 16  16th
 17  17th
 18  18th
 19  19th
 20  20th
 21  21st
 22  22nd
 23  23rd
 24  24th
 25  25th
 26  26th
 27  27th
 28  28th
 29  29th
 30  30th
 31  31st
 32  32nd
 33  33rd
 34  34th
 35  35th
 36  36th
 37  37th
 38  38th
 39  39th
 40  40th
 41  41st
 42  42nd
 43  43rd
 44  44th
 45  45th
 46  46th
 47  47th
 48  48th
 49  49th
 50  50th
 51  51st
 52  52nd
 53  53rd
 54  54th
 55  55th
 56  56th
 57  57th
 58  58th
 59  59th
 60  60th
 61  61st
 62  62nd
 63  63rd
 64  64th
 65  65th
 66  66th
 67  67th
 68  68th
 69  69th
 70  70th
 71  71st
 72  72nd
 73  73rd
 74  74th
 75  75th
 76  76th
 77  77th
 78  78th
 79  79th
 80  80th
 81  81st
 82  82nd
 83  83rd
 84  84th
 85  85th
 86  86th
 87  87th
 88  88th
 89  89th
 90  90th
 91  91st
 92  92nd
 93  93rd
 94  94th
 95  95th
 96  96th
 97  97th
 98  98th
 99  99th
100  100th
101  101st
102  102nd
103  103rd
104  104th
105  105th
106  106th
107  107th
108  108th
109  109th
110  110th
111  111th
112  112th
113  113th
114  114th
115  115th
Salman A
sumber
1
Ini bekerja sangat baik untuk saya juga: dateString = monthNames [newValue.getUTCMonth ()] + "" + numberSuffix (newValue.getUTCDate ()) + "," + newValue.getUTCFullYear ();
Michael J. Calkins
9
Ini tidak menangani pengecualian untuk tiga angka "remaja" dengan benar. Misalnya nomor 111, 112dan 113harus menghasilkan "111th", "112th"dan "113th"masing-masing, bukan dengan "111st", "112nd", dan "113rd"diproduksi oleh fungsi sebagai saat kode.
martineau
3
Jawaban ini tampaknya telah berkembang sempurna. Terima kasih untuk semua kontributor.
Lonnie Best
7
Saya menganggapnya sebagai lambda ES6 tanpa alasan yang jelas:n=>n+(n%10==1&&n%100!=11?'st':n%10==2&&n%100!=12?'nd':n%10==3&&n%100!=13?'rd':'th')
Camilo Martin
1
@Anomaly cukup lucu, setelah ~ π / 2 tahun kemudian saya masih bisa membacanya.
Camilo Martin
211

Dari Shopify

function getNumberWithOrdinal(n) {
  var s = ["th", "st", "nd", "rd"],
      v = n % 100;
  return n + (s[(v - 20) % 10] || s[v] || s[0]);
}

[-4,-1,0,1,2,3,4,10,11,12,13,14,20,21,22,100,101,111].forEach(
  n => console.log(n + ' -> ' + getNumberWithOrdinal(n))
);

Fizer Khan
sumber
22
Menambahkan penjelasan dapat membuatnya menjadi jawaban yang lebih baik!
Pugazh
5
@Pugazh A. temukan s [v% 10] jika> = 20 (ke-20 ... ke-99), B. jika tidak ditemukan, coba s [v] (ke-0.3), C. jika masih tidak ditemukan, gunakan s [0] (4th.19)
Sheepy
4
mengapa dobel mendapatkan nama fungsi?
Gisheri
46

Pendekatan minimal satu baris untuk sufiks ordinal

function nth(n){return["st","nd","rd"][((n+90)%100-10)%10-1]||"th"}

(ini untuk bilangan bulat positif, lihat di bawah untuk variasi lain)

Penjelasan

Mulailah dengan array dengan sufiks ["st", "nd", "rd"]. Kami ingin memetakan bilangan bulat yang diakhiri dengan 1, 2, 3 (tetapi tidak berakhir pada 11, 12, 13) dengan indeks 0, 1, 2.

Bilangan bulat lainnya (termasuk yang berakhir pada 11, 12, 13) dapat dipetakan ke hal lain — indeks yang tidak ditemukan dalam array akan dievaluasi undefined. Ini salah dalam javascript dan dengan penggunaan logis atau ( || "th") ekspresi akan kembali "th"untuk bilangan bulat ini, yang persis seperti yang kita inginkan.

Ekspresi ((n + 90) % 100 - 10) % 10 - 1melakukan pemetaan. Hancurkan:

  • (n + 90) % 100: Ekspresi ini mengambil integer input - 10 mod 100, memetakan 10 hingga 0, ... 99 hingga 89, 0 hingga 90, ..., 9 hingga 99. Sekarang bilangan bulat yang diakhiri dengan 11, 12, 13 berada di bagian bawah akhir (dipetakan ke 1, 2, 3).
  • - 10: Sekarang 10 dipetakan ke −10, 19 hingga −1, 99 hingga 79, 0 hingga 80, ... 9 hingga 89. Bilangan bulat yang diakhiri dengan 11, 12, 13 dipetakan ke bilangan bulat negatif (−9, −8, −7).
  • % 10: Sekarang semua bilangan bulat yang diakhiri dengan 1, 2, atau 3 dipetakan ke 1, 2, 3. Semua bilangan bulat lainnya dipetakan ke sesuatu yang lain (11, 12, 13 masih dipetakan ke −9, −8, −7).
  • - 1: Mengurangi satu memberikan pemetaan akhir dari 1, 2, 3 ke 0, 1, 2

Memverifikasi bahwa itu berfungsi

function nth(n){return["st","nd","rd"][((n+90)%100-10)%10-1]||"th"}

//test integers from 1 to 124
for(var r = [], i = 1; i < 125; i++) r.push(i + nth(i));

//output result
document.getElementById('result').innerHTML = r.join('<br>');
<div id="result"></div>

Variasi

Mengizinkan bilangan bulat negatif:

function nth(n){return["st","nd","rd"][(((n<0?-n:n)+90)%100-10)%10-1]||"th"}

Dalam sintaks panah lemak ES6 (fungsi anonim):

n=>["st","nd","rd"][(((n<0?-n:n)+90)%100-10)%10-1]||"th"

Memperbarui

Alternatif yang lebih pendek untuk bilangan bulat positif adalah ekspresi

[,'st','nd','rd'][n%100>>3^1&&n%10]||'th'

Lihat posting ini untuk penjelasan.

Perbarui 2

[,'st','nd','rd'][n/10%10^1&&n%10]||'th'
Tomas Langkaas
sumber
3
anggun. kesukaanku.
guy mograbi
10

Intl.PluralRules, metode standar .

Saya hanya ingin menjatuhkan cara kanonik melakukan ini di sini, karena sepertinya tidak ada yang mengetahuinya.

const english_ordinal_rules = new Intl.PluralRules("en", {type: "ordinal"});
const suffixes = {
	one: "st",
	two: "nd",
	few: "rd",
	other: "th"
};
function ordinal(number) {
	const suffix = suffixes[english_ordinal_rules.select(number)];
	return (number + suffix);
}

const test = Array(201)
	.fill()
	.map((_, index) => index - 100)
	.map(ordinal)
	.join(" ");
console.log(test);

Константин Ван
sumber
1
Ini adalah satu-satunya solusi umum yang baik karena satu-satunya jawaban di sini yang menangani angka negatif.
RobG
7

Anda hanya punya 12 hari? Saya akan tergoda untuk membuatnya hanya array pencarian sederhana:

var suffixes = ['','st','nd','rd','th','th','th','th','th','th','th','th','th'];

kemudian

var i = 2;
var day = i + suffixes[i]; // result: '2nd'

atau

var i = 8;
var day = i + suffixes[i]; // result: '8th'
Jamiec
sumber
Terima kasih, ini menyelesaikan masalah saya. Saya tidak bisa mendapatkan sufiks yang cocok dengan hari jadi saya hanya mengisi array dengan, keduanya, angka dan sufiks yang bekerja dengan sempurna. Saya kemudian menyebutnya seperti$("#dynamicTitle span").html(suffix[i-1]);
Antonio Vasilev
7

Dengan memisahkan angka menjadi array dan membalikkan, kita dapat dengan mudah memeriksa 2 digit terakhir dari angka menggunakan array[0]dan array[1].

Jika angka di remaja array[1] = 1itu membutuhkan "th".

function getDaySuffix(num)
{
    var array = ("" + num).split("").reverse(); // E.g. 123 = array("3","2","1")

    if (array[1] != "1") { // Number is in the teens
        switch (array[0]) {
            case "1": return "st";
            case "2": return "nd";
            case "3": return "rd";
        }
    }

    return "th";
}
nick
sumber
Ini sempurna. Terima kasih!
Jason
Anda harus mengecualikan 11, 12, 13
psx
2
@psx Itulah kondisi untuk jalur 5.
nick
4
function getSuffix(n) {return n < 11 || n > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((n - 1) % 10, 3)] : 'th'}
Johnny
sumber
Oneliner kecil yang menyenangkan, hanya sedikit sulit untuk dipahami
bryc
Gagal di mana n == 0 karena n - 1sebagian (pengembalian tidak ditentukan). Juga gagal untuk angka yang lebih besar dari 110, misalnya getSuffix(111)mengembalikan "st". Itu memecahkan masalah OP di mana angka 1 hingga 12, tetapi bukan solusi umum. :-(
RobG
2

Saya menulis fungsi ini untuk menyelesaikan masalah ini:

// this is for adding the ordinal suffix, turning 1, 2 and 3 into 1st, 2nd and 3rd
Number.prototype.addSuffix=function(){
    var n=this.toString().split('.')[0];
    var lastDigits=n.substring(n.length-2);
    //add exception just for 11, 12 and 13
    if(lastDigits==='11' || lastDigits==='12' || lastDigits==='13'){
        return this+'th';
    }
    switch(n.substring(n.length-1)){
        case '1': return this+'st';
        case '2': return this+'nd';
        case '3': return this+'rd';
        default : return this+'th';
    }
};

Dengan ini, Anda bisa memasukkan .addSuffix()nomor apa saja dan itu akan menghasilkan apa yang Anda inginkan. Sebagai contoh:

var number=1234;
console.log(number.addSuffix());
// console will show: 1234th
Jimmery
sumber
Saya pikir numberdalam string ini var lastDigits=n.substring(number.length-2);harus diubah menjadithis
Slava Abakumov
seharusnya nbukan this, tapi terima kasih telah menunjukkan bug itu! :)
Jimmery
2

Versi alternatif dari fungsi ordinal dapat sebagai berikut:

function toCardinal(num) {
    var ones = num % 10;
    var tens = num % 100;

    if (tens < 11 || tens > 13) {
        switch (ones) {
            case 1:
                return num + "st";
            case 2:
                return num + "nd";
            case 3:
                return num + "rd";
        }
    }

    return num + "th";
}

Variabel diberi nama lebih eksplisit, menggunakan konvensi kasus unta, dan mungkin lebih cepat.

Daniel Harvey
sumber
Namun ini tidak akan berfungsi untuk basis kode yang dilokalkan.
Daniel Harvey
1

Saya menulis fungsi sederhana ini tempo hari. Meskipun untuk kencan Anda tidak perlu angka yang lebih besar, ini juga akan memenuhi nilai yang lebih tinggi (1013, 36021 dll ...)

var fGetSuffix = function(nPos){

    var sSuffix = "";

    switch (nPos % 10){
        case 1:
            sSuffix = (nPos % 100 === 11) ? "th" : "st";
            break;
        case 2:
            sSuffix = (nPos % 100 === 12) ? "th" : "nd";
            break;
        case 3:
            sSuffix = (nPos % 100 === 13) ? "th" : "rd";
            break;
        default:
            sSuffix = "th";
            break;
    }

    return sSuffix;
};
Sir Kettle
sumber
1

function ordsfx(a){return["th","st","nd","rd"][(a=~~(a<0?-a:a)%100)>10&&a<14||(a%=10)>3?0:a]}

Lihat versi beranotasi di https://gist.github.com/furf/986113#file-annotated-js

Singkat, manis, dan efisien, sama seperti fungsi utilitas seharusnya. Bekerja dengan bilangan bulat / float yang ditandatangani / tidak ditandatangani. (Meskipun saya tidak bisa membayangkan kebutuhan untuk menahbiskan mengapung)

hndcrftd
sumber
0

Ini pilihan lain.

function getOrdinalSuffix(day) {
        
   	if(/^[2-3]?1$/.test(day)){
   		return 'st';
   	} else if(/^[2-3]?2$/.test(day)){
   		return 'nd';
   	} else if(/^[2-3]?3$/.test(day)){
   		return 'rd';
   	} else {
   		return 'th';
   	}
        
}
    
console.log(getOrdinalSuffix('1'));
console.log(getOrdinalSuffix('13'));
console.log(getOrdinalSuffix('22'));
console.log(getOrdinalSuffix('33'));

Perhatikan pengecualian untuk remaja? Remaja sangat akward!

Sunting: Lupa tentang tanggal 11 dan 12

Bullyen
sumber
0

Saya ingin memberikan jawaban fungsional untuk pertanyaan ini untuk melengkapi jawaban yang ada:

const ordinalSuffix = ['st', 'nd', 'rd']
const addSuffix = n => n + (ordinalSuffix[(n - 1) % 10] || 'th')
const numberToOrdinal = n => `${n}`.match(/1\d$/) ? n + 'th' : addSuffix(n)

kami telah membuat array nilai khusus, yang penting untuk diingat adalah array memiliki indeks berbasis nol sehingga ordinalSuffix [0] sama dengan 'st'.

Fungsi kami numberToOrdinal memeriksa apakah nomor tersebut diakhiri dengan nomor remaja di mana case menambahkan nomor dengan 'th' karena semua nomor maka ordinals adalah 'th'. Dalam hal nomor tersebut bukan remaja, kami meneruskan nomor tersebut ke addSuffix yang menambahkan nomor ke ordinal yang ditentukan oleh jika angka minus 1 (karena kami menggunakan indeks berbasis nol) mod 10 memiliki sisa 2 atau kurang itu diambil dari array, kalau tidak itu 'th'.

output sampel:

numberToOrdinal(1) // 1st
numberToOrdinal(2) // 2nd
numberToOrdinal(3) // 3rd
numberToOrdinal(4) // 4th
numberToOrdinal(5) // 5th
numberToOrdinal(6) // 6th
numberToOrdinal(7) // 7th
numberToOrdinal(8) // 8th
numberToOrdinal(9) // 9th
numberToOrdinal(10) // 10th
numberToOrdinal(11) // 11th
numberToOrdinal(12) // 12th
numberToOrdinal(13) // 13th
numberToOrdinal(14) // 14th
numberToOrdinal(101) // 101st
Peter McArthur
sumber
0

Yang lama saya buat untuk barang-barang saya ...

function convertToOrdinal(number){
    if (number !=1){
        var numberastext = number.ToString();
        var endchar = numberastext.Substring(numberastext.Length - 1);
        if (number>9){
            var secondfromendchar = numberastext.Substring(numberastext.Length - 1);
            secondfromendchar = numberastext.Remove(numberastext.Length - 1);
        }
        var suffix = "th";
        var digit = int.Parse(endchar);
        switch (digit){
            case 3:
                if(secondfromendchar != "1"){
                    suffix = "rd";
                    break;
                }
            case 2:
                if(secondfromendchar != "1"){
                    suffix = "nd";
                    break;
                }
            case 1:
                if(secondfromendchar != "1"){
                    suffix = "st";
                    break;
                }
            default:
                suffix = "th";
                break;
         }
            return number+suffix+" ";
     } else {
            return;
     }
}
pengguna10304
sumber
Tambahkan beberapa deskripsi tentang kode di atas. Ini akan membantu lebih dari sekadar sepotong kode.
Mathews Sunny
0

Sangat merekomendasikan perpustakaan tanggal-fns yang sangat baik . Cepat, modular, tidak berubah, bekerja dengan tanggal standar.

import * as DateFns from 'date-fns';

const ordinalInt = DateFns.format(someInt, 'do');

Lihat date-fns docs: https://date-fns.org/v2.0.0-alpha.9/docs/format

Freewalker
sumber
0

Saya menulis fungsi ini untuk angka yang lebih tinggi dan semua kasus uji

function numberToOrdinal(num) {
    if (num === 0) {
        return '0'
    };
    let i = num.toString(), j = i.slice(i.length - 2), k = i.slice(i.length - 1);
    if (j >= 10 && j <= 20) {
        return (i + 'th')
    } else if (j > 20 && j < 100) {
        if (k == 1) {
            return (i + 'st')
        } else if (k == 2) {
            return (i + 'nd')
        } else if (k == 3) {
            return (i + 'rd')
        } else {
            return (i + 'th')
        }
    } else if (j == 1) {
        return (i + 'st')
    } else if (j == 2) {
        return (i + 'nd')
    } else if (j == 3) {
        return (i + 'rd')
    } else {
        return (i + 'th')
    }
}
Amaechi chuks
sumber
0

Ini pendekatan yang sedikit berbeda (saya kira jawaban lain tidak melakukan ini). Saya tidak yakin apakah saya menyukainya atau membencinya, tetapi itu berhasil!

export function addDaySuffix(day: number) { 
  const suffixes =
      '  stndrdthththththththththththththththththstndrdthththththththst';
    const startIndex = day * 2;

    return `${day}${suffixes.substring(startIndex, startIndex + 2)}`;
  }
Dave Cooper
sumber
0

Ini untuk satu liners dan pecinta es6

let i= new Date().getDate 

// I can be any number, for future sake we'll use 9

const j = I % 10;
const k = I % 100;

i = `${i}${j === 1 &&  k !== 11 ? 'st' : j === 2 && k !== 12 ? 'nd' : j === 3 && k !== 13 ? 'rd' : 'th'}`}

console.log(i) //9th

Pilihan lain untuk + menjadi nomor adalah:

console.log(["st","nd","rd"][((i+90)%100-10)%10-1]||"th"]

Juga untuk menyingkirkan awalan ordinal cukup gunakan ini:

console.log(i.parseInt("8th"))

console.log(i.parseFloat("8th"))

jangan ragu untuk memodifikasi sesuai dengan yang Anda butuhkan

Pedro JR
sumber
0

Anda juga dapat menggunakan scales::ordinal()fungsi ini. Cepat dan mudah digunakan.

scales::ordinal(1:12)
## [1] "1st"  "2nd"  "3rd"  "4th"  "5th"  "6th"  "7th"  "8th"  "9th"  "10th" "11th" "12th"
phargart
sumber
-1

Saya sangat merekomendasikan ini, sangat mudah dan mudah dibaca. Saya harap ini membantu?

  • Ini menghindari penggunaan bilangan bulat negatif yaitu angka kurang dari 1 dan mengembalikan false
  • Ini mengembalikan 0 jika inputnya 0
function numberToOrdinal(n) {

  let result;

  if(n < 0){
    return false;
  }else if(n === 0){
    result = "0";
  }else if(n > 0){

    let nToString = n.toString();
    let lastStringIndex = nToString.length-1;
    let lastStringElement = nToString[lastStringIndex];

    if( lastStringElement == "1" && n % 100 !== 11 ){
      result = nToString + "st";
    }else if( lastStringElement == "2" && n % 100 !== 12 ){
      result = nToString + "nd";
    }else if( lastStringElement == "3" && n % 100 !== 13 ){
      result = nToString + "rd";
    }else{
      result = nToString + "th";
    }

  }

  return result;
}

console.log(numberToOrdinal(-111));
console.log(numberToOrdinal(0));
console.log(numberToOrdinal(11));
console.log(numberToOrdinal(15));
console.log(numberToOrdinal(21));
console.log(numberToOrdinal(32));
console.log(numberToOrdinal(43));
console.log(numberToOrdinal(70));
console.log(numberToOrdinal(111));
console.log(numberToOrdinal(300));
console.log(numberToOrdinal(101));

KELUARAN

false
0
11th
15th
21st
32nd
43rd
70th
111th
300th
101st
an-apluss
sumber
-7

<p>31<sup>st</sup> March 2015</p>

Kamu bisa memakai

1<sup>st</sup> 2<sup>nd</sup> 3<sup>rd</sup> 4<sup>th</sup>

untuk memposisikan akhiran

Wisnu Vikraman
sumber
4
Ini bukan yang diminta OP
TetraDev