Project

General

Profile

« Previous | Next » 

Revision 6561

move the DataONE 1.0.0-SNAPSHOT

View differences:

test/edu/ucsb/nceas/metacat/dataone/MNodeServiceTest.java
509 509
      Identifier pid = MNodeService.getInstance(request).create(session, guid, object, sysmeta);
510 510
      DescribeResponse describeResponse = MNodeService.getInstance(request).describe(session, pid);
511 511
      assertEquals(describeResponse.getDataONE_Checksum().getValue(), sysmeta.getChecksum().getValue());
512
      assertEquals(describeResponse.getDataONE_ObjectFormatIdentifier(), sysmeta.getFmtid());
512
      assertEquals(describeResponse.getDataONE_ObjectFormatIdentifier(), sysmeta.getFormatId());
513 513
      
514 514
    } catch (UnsupportedEncodingException e) {
515 515
      e.printStackTrace();
test/edu/ucsb/nceas/metacat/dataone/CNodeServiceTest.java
548 548
    try {
549 549
	    
550 550
			String result = 
551
				CNodeService.getInstance(request).getFormat(fmtid).getFmtid().getValue();
551
				CNodeService.getInstance(request).getFormat(fmtid).getFormatId().getValue();
552 552
	  	System.out.println("Expected result: " + knownFormat);
553 553
	  	System.out.println("Found    result: " + result);
554 554
	  	assertTrue(result.equals(knownFormat));
test/edu/ucsb/nceas/metacat/dataone/D1NodeServiceTest.java
150 150
	  throws Exception
151 151
	{
152 152
	    SystemMetadata sm = new SystemMetadata();
153
	    sm.setSerialVersion(BigInteger.valueOf(1));
153 154
        // set the id
154 155
        sm.setIdentifier(id);
155
        sm.setFmtid(ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFmtid());
156
        sm.setFormatId(ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFormatId());
156 157
        // create the checksum
157 158
        String checksumS = "test";
158 159
        if (object != null) {
src/upgrade-db-to-2.0.0-oracle.sql
1 1
CREATE TABLE systemMetadata (
2 2
   guid   VARCHAR2(2000),    -- the globally unique string identifier
3
   serial_version VARCHAR2(256), --the serial version of the object
3 4
   date_uploaded DATE, -- the date/time the document was first submitted
4 5
   rights_holder VARCHAR2(250), --the user who has rights to the document, usually the first persons to upload it
5 6
   checksum VARCHAR2(512), --the checksum of the doc using the given algorithm (see below)
src/xmltables-oracle.sql
404 404
 */
405 405
CREATE TABLE systemMetadata (
406 406
   guid   VARCHAR2(2000),    -- the globally unique string identifier
407
   serial_version VARCHAR2(256), --the serial version of the object   
407 408
   date_uploaded DATE, -- the date/time the document was first submitted
408 409
   rights_holder VARCHAR2(250), --the user who has rights to the document, usually the first persons to upload it
409 410
   checksum VARCHAR2(512), --the checksum of the doc using the given algorithm (see below)
src/upgrade-db-to-2.0.0-postgres.sql
1 1
CREATE TABLE systemMetadata (
2 2
	guid   text,          -- the globally unique string identifier of the object that the system metadata describes
3
	serial_version VARCHAR(256), --the serial version of the object
3 4
	date_uploaded TIMESTAMP, -- the date/time the document was first submitted
4 5
	rights_holder VARCHAR(250), --the user who has rights to the document, usually the first persons to upload it
5 6
	checksum VARCHAR(512), --the checksum of the doc using the given algorithm (see below)
src/xmltables-postgres.sql
296 296
 */
297 297
CREATE TABLE systemMetadata (
298 298
	guid   text,          -- the globally unique string identifier of the object that the system metadata describes
299
	serial_version VARCHAR(256), --the serial version of the object
299 300
	date_uploaded TIMESTAMP, -- the date/time the document was first submitted
300 301
	rights_holder VARCHAR(250), --the user who has rights to the document, usually the first persons to upload it
301 302
	checksum VARCHAR(512), --the checksum of the doc using the given algorithm (see below)
src/edu/ucsb/nceas/metacat/restservice/MNResourceHandler.java
405 405

  
406 406
            if (params.containsKey("formatId")) {
407 407
                String f = params.get("formatId")[0];
408
                fmtid = ObjectFormatCache.getInstance().getFormat(f).getFmtid();
408
                fmtid = ObjectFormatCache.getInstance().getFormat(f).getFormatId();
409 409
            }
410 410
            
411 411
            if (params.containsKey("fromDate")) {
......
676 676
            SystemMetadata sm = MNodeService.getInstance(request).getSystemMetadata(session, id);
677 677
            
678 678
            //set the content type
679
            if (sm.getFmtid().getValue().trim().equals(
680
            		ObjectFormatCache.getInstance().getFormat("text/csv").getFmtid().getValue()))
679
            if (sm.getFormatId().getValue().trim().equals(
680
            		ObjectFormatCache.getInstance().getFormat("text/csv").getFormatId().getValue()))
681 681
            {
682 682
                response.setContentType("text/csv");
683 683
                response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".csv");
684 684
            }
685
            else if (sm.getFmtid().getValue().trim().equals(
686
            		ObjectFormatCache.getInstance().getFormat("text/plain").getFmtid().getValue()))
685
            else if (sm.getFormatId().getValue().trim().equals(
686
            		ObjectFormatCache.getInstance().getFormat("text/plain").getFormatId().getValue()))
687 687
            {
688 688
                response.setContentType("text/plain");
689 689
                response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".txt");
690 690
            } 
691
            else if (sm.getFmtid().getValue().trim().equals(
692
            		ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFmtid().getValue()))
691
            else if (sm.getFormatId().getValue().trim().equals(
692
            		ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFormatId().getValue()))
693 693
            {
694 694
                response.setContentType("application/octet-stream");
695 695
            }
......
779 779
            ObjectFormatIdentifier fmtid = null;
780 780
           
781 781
            if ( objectFormat != null ) {
782
          	 fmtid = objectFormat.getFmtid();
782
          	 fmtid = objectFormat.getFormatId();
783 783
          	 
784 784
            }
785 785
            ObjectList ol = 
src/edu/ucsb/nceas/metacat/restservice/CNResourceHandler.java
424 424
        SystemMetadata sm = CNodeService.getInstance(request).getSystemMetadata(session, id);
425 425
        
426 426
        //set the content type
427
        if(sm.getFmtid().getValue().trim().equals(
428
        		ObjectFormatCache.getInstance().getFormat("text/csv").getFmtid().getValue()))
427
        if(sm.getFormatId().getValue().trim().equals(
428
        		ObjectFormatCache.getInstance().getFormat("text/csv").getFormatId().getValue()))
429 429
        {
430 430
            response.setContentType("text/csv");
431 431
            response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".csv");
432 432
        }
433
        else if(sm.getFmtid().getValue().trim().equals(
434
        		ObjectFormatCache.getInstance().getFormat("text/plain").getFmtid().getValue()))
433
        else if(sm.getFormatId().getValue().trim().equals(
434
        		ObjectFormatCache.getInstance().getFormat("text/plain").getFormatId().getValue()))
435 435
        {
436 436
            response.setContentType("text/plain");
437 437
            response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".txt");
438 438
        } 
439
        else if(sm.getFmtid().getValue().trim().equals(
440
        		ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFmtid().getValue()))
439
        else if(sm.getFormatId().getValue().trim().equals(
440
        		ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFormatId().getValue()))
441 441
        {
442 442
            response.setContentType("application/octet-stream");
443 443
        }
src/edu/ucsb/nceas/metacat/MetacatHandler.java
3526 3526
      
3527 3527
      // create system metadata for the document
3528 3528
      SystemMetadata sysMeta = new SystemMetadata();
3529
      sysMeta.setSerialVersion(BigInteger.valueOf(1));
3529 3530
      int rev = IdentifierManager.getInstance().getLatestRevForLocalId(localId);
3530 3531
      AccessionNumber accNum = new AccessionNumber(localId, "NONE");
3531 3532
      String guid = null;
......
3592 3593
      
3593 3594
      // set the object format, fall back to defaults
3594 3595
      try {
3595
	      fmtid = ObjectFormatCache.getInstance().getFormat(doctype).getFmtid();
3596
	      fmtid = ObjectFormatCache.getInstance().getFormat(doctype).getFormatId();
3596 3597

  
3597 3598
      } catch (NotFound nfe) {
3598 3599
        
......
3600 3601
        	// format is not registered, use default
3601 3602
	        if (doctype.trim().equals("BIN")) {
3602 3603
	        	fmtid = ObjectFormatCache.getInstance().getFormat(
3603
	        			"application/octet-stream").getFmtid();
3604
	        			"application/octet-stream").getFormatId();
3604 3605
	        
3605 3606
	        } else {
3606
	        	fmtid = ObjectFormatCache.getInstance().getFormat("text/plain").getFmtid();
3607
	        	fmtid = ObjectFormatCache.getInstance().getFormat("text/plain").getFormatId();
3607 3608
	        }
3608 3609
        
3609 3610
        } catch (NotFound nf) {
......
3614 3615

  
3615 3616
      }
3616 3617
      
3617
      sysMeta.setFmtid(fmtid);
3618
      sysMeta.setFormatId(fmtid);
3618 3619
      logMetacat.debug("The ObjectFormat for " + localId + " is " + fmtid.getValue());
3619 3620
      
3620 3621
      // further parse EML documents to get data object format,
3621 3622
      // describes and describedBy information
3622
      if ( fmtid == ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.0.0").getFmtid() ||
3623
           fmtid == ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.0.1").getFmtid() ||
3624
           fmtid == ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.1.0").getFmtid() ||
3625
           fmtid == ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.1.1").getFmtid() ) {
3623
      if ( fmtid == ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.0.0").getFormatId() ||
3624
           fmtid == ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.0.1").getFormatId() ||
3625
           fmtid == ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.1.0").getFormatId() ||
3626
           fmtid == ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.1.1").getFormatId() ) {
3626 3627
        
3627 3628
        try {
3628 3629
        	
......
3643 3644
            // default to binary
3644 3645
            if (dataDocMimeType == null) {
3645 3646
                dataDocMimeType = 
3646
                	ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFmtid().getValue();
3647
                	ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFormatId().getValue();
3647 3648
            }
3648 3649
            String dataDocLocalId = "";
3649 3650
            logMetacat.debug("Data local ID: " + dataDocLocalId);
......
3684 3685
                      logMetacat.debug("Updating system metadata for " + dataGuid.getValue() + " to " + dataDocMimeType);
3685 3686
                      try {
3686 3687
	                      ObjectFormatIdentifier fmt = 
3687
	                      ObjectFormatCache.getInstance().getFormat(dataDocMimeType).getFmtid();
3688
	                      dataSysMeta.setFmtid(fmt);
3688
	                      ObjectFormatCache.getInstance().getFormat(dataDocMimeType).getFormatId();
3689
	                      dataSysMeta.setFormatId(fmt);
3689 3690
                      
3690 3691
                      } catch (NotFound nfe) {
3691 3692
                      	logMetacat.debug("Couldn't find format identifier for: " +
src/edu/ucsb/nceas/metacat/util/MetacatPopulator.java
177 177
	                String dataDocMimeType = dataPackage.getEntityList()[j].getDataFormat();
178 178
	                if (dataDocMimeType == null) {
179 179
		                dataDocMimeType = 
180
		                	ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFmtid().getValue();
180
		                	ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFormatId().getValue();
181 181
	                }
182 182
	                String dataDocLocalId = "";
183 183
	                if (dataDocUrl.trim().startsWith("ecogrid://knb/")) { //we only handle ecogrid urls right now
......
202 202
	                    ObjectFormat format = null;
203 203
	                    try {
204 204
	                    	format = ObjectFormatCache.getInstance().getFormat(dataDocMimeType);
205
							dataDocSysMeta.setFmtid(format.getFmtid());
205
							dataDocSysMeta.setFormatId(format.getFormatId());
206 206
	                    } catch (NotFound e) {
207 207
							System.out.println(e.getMessage());
208 208
						}
......
291 291
    private SystemMetadata generateSystemMetadata(Document doc)
292 292
      throws Exception {
293 293
        SystemMetadata sm = new SystemMetadata();
294
        sm.setSerialVersion(BigInteger.valueOf(1));
294 295
        //set the id
295 296
        Identifier id = new Identifier();
296 297
        id.setValue(doc.docid.trim());
......
306 307
                format = ObjectFormatCache.getInstance().getFormat("text/plain");
307 308
            }
308 309
        }
309
        sm.setFmtid(format.getFmtid());
310
        sm.setFormatId(format.getFormatId());
310 311
        
311 312
        //create the checksum
312 313
        ByteArrayInputStream bais = new ByteArrayInputStream(doc.doctext.getBytes(MetaCatServlet.DEFAULT_ENCODING));
src/edu/ucsb/nceas/metacat/dataone/ObjectFormatService.java
240 240
		for (int i = 0; i < listSize; i++) {
241 241

  
242 242
			ObjectFormat objectFormat = objectFormatList.getObjectFormat(i);
243
			String identifier = objectFormat.getFmtid().getValue();
243
			String identifier = objectFormat.getFormatId().getValue();
244 244
			getObjectFormatMap().put(identifier, objectFormat);
245 245

  
246 246
		}
src/edu/ucsb/nceas/metacat/dataone/MNodeService.java
482 482

  
483 483
    	// get system metadata and construct the describe response
484 484
        SystemMetadata sysmeta = getSystemMetadata(session, pid);
485
        DescribeResponse describeResponse = new DescribeResponse(sysmeta.getFmtid(), sysmeta.getSize(), sysmeta.getDateSysMetadataModified(),
485
        DescribeResponse describeResponse = new DescribeResponse(sysmeta.getFormatId(), sysmeta.getSize(), sysmeta.getDateSysMetadataModified(),
486 486
                sysmeta.getChecksum());
487 487

  
488 488
        return describeResponse;
......
802 802
                // if we are filtering by format
803 803
                if (formatId != null) {
804 804
                    SystemMetadata sysmeta = IdentifierManager.getInstance().getSystemMetadata(pid.getValue());
805
                    if (!sysmeta.getFmtid().getValue().equals(formatId.getValue())) {
805
                    if (!sysmeta.getFormatId().getValue().equals(formatId.getValue())) {
806 806
                        // does not match
807 807
                        continue;
808 808
                    }
src/edu/ucsb/nceas/metacat/dataone/MetadataTypeRegister.java
58 58
            while(vals.hasNext())
59 59
            {
60 60
                String val = vals.next();
61
                String ofVal = format.getFmtid().getValue();
61
                String ofVal = format.getFormatId().getValue();
62 62
                //System.out.println("val: " + val);
63 63
                if(val.trim().equals(ofVal.trim()))
64 64
                {
src/edu/ucsb/nceas/metacat/dataone/D1NodeService.java
714 714
    boolean isScienceMetadata = false;
715 715
    
716 716
    try {
717
      objectFormat = ObjectFormatCache.getInstance().getFormat(sysmeta.getFmtid());
717
      objectFormat = ObjectFormatCache.getInstance().getFormat(sysmeta.getFormatId());
718 718
      if ( objectFormat.getFormatType().equals("METADATA") ) {
719 719
      	isScienceMetadata = true;
720 720
      	
src/edu/ucsb/nceas/metacat/IdentifierManager.java
108 108
    public SystemMetadata asSystemMetadata(Date dateUploaded, String rightsHolder,
109 109
            String checksum, String checksumAlgorithm, String originMemberNode,
110 110
            String authoritativeMemberNode, Date dateModified, String submitter, 
111
            String guid, String fmtidStr, BigInteger size) {
111
            String guid, String fmtidStr, BigInteger size, BigInteger serialVersion) {
112 112
        SystemMetadata sysMeta = new SystemMetadata();
113 113

  
114 114
        Identifier sysMetaId = new Identifier();
......
134 134
        sysMeta.setSubmitter(submitterSubject);
135 135
        try {
136 136
        	ObjectFormatIdentifier fmtid = 
137
        		ObjectFormatCache.getInstance().getFormat(fmtidStr).getFmtid();
138
        	sysMeta.setFmtid(fmtid);
137
        		ObjectFormatCache.getInstance().getFormat(fmtidStr).getFormatId();
138
        	sysMeta.setFormatId(fmtid);
139 139
        } catch (NotFound nfe) {
140 140
          logMetacat.error("The objectFormat " + fmtidStr +
141 141
          	" is not registered. Setting the default format id.");
142 142
          ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
143 143
          fmtid.setValue("application/octet-stream");
144
          sysMeta.setFmtid(fmtid);
144
          sysMeta.setFormatId(fmtid);
145 145
        }
146 146
        sysMeta.setSize(size);
147
        sysMeta.setSerialVersion(serialVersion);
147 148
        
148 149
        return sysMeta;
149 150
    }
......
244 245
        SystemMetadata sysMeta = new SystemMetadata();
245 246
        String sql = "select guid, date_uploaded, rights_holder, checksum, checksum_algorithm, " +
246 247
          "origin_member_node, authoritive_member_node, date_modified, submitter, object_format, size, " +
247
          "replication_allowed, number_replicas, obsoletes, obsoleted_by " +
248
          "replication_allowed, number_replicas, obsoletes, obsoleted_by, serial_version " +
248 249
          "from systemmetadata where guid = ?";
249 250
        DBConnection dbConn = null;
250 251
        int serialNumber = -1;
251 252
        Boolean replicationAllowed = new Boolean(false);
252 253
        BigInteger numberOfReplicas = new BigInteger("-1");
253
        
254
        BigInteger serialVersion = new BigInteger("-1");
255

  
254 256
        try 
255 257
        {
256 258
            // Get a database connection from the pool
......
277 279
                numberOfReplicas = new BigInteger(rs.getString(13));
278 280
                String obsoletes = rs.getString(14);
279 281
                String obsoletedBy = rs.getString(15);
282
                serialVersion = new BigInteger(rs.getString(16));
280 283

  
284

  
281 285
                Identifier sysMetaId = new Identifier();
282 286
                sysMetaId.setValue(guid);
283 287
                sysMeta.setIdentifier(sysMetaId);
288
                sysMeta.setSerialVersion(serialVersion);
284 289
                sysMeta.setDateUploaded(dateUploaded);
285 290
                Subject rightsHolderSubject = new Subject();
286 291
                rightsHolderSubject.setValue(rightsHolder);
......
305 310
                sysMeta.setSubmitter(submitterSubject);
306 311
                try {
307 312
                	ObjectFormatIdentifier fmtid = 
308
                		ObjectFormatCache.getInstance().getFormat(fmtidStr).getFmtid();
309
                	sysMeta.setFmtid(fmtid);
313
                		ObjectFormatCache.getInstance().getFormat(fmtidStr).getFormatId();
314
                	sysMeta.setFormatId(fmtid);
310 315
                } catch (NotFound nfe) {
311 316
                  logMetacat.error("The objectFormat " + fmtidStr +
312 317
                  	" is not registered. Setting the default format id.");
313 318
                  ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
314 319
                  fmtid.setValue("application/octet-stream");
315
                  sysMeta.setFmtid(fmtid);
320
                  sysMeta.setFormatId(fmtid);
316 321
                }
317 322
                sysMeta.setSize(size);
318 323
                if (obsoletes != null) {
......
1067 1072
            String checksum, String checksumAlgorithm, String originMemberNode,
1068 1073
            String authoritativeMemberNode, long modifiedDate, String submitter, 
1069 1074
            String guid, String objectFormat, BigInteger size, boolean replicationAllowed,
1070
            int numberReplicas, String obsoletes, String obsoletedBy)
1075
            int numberReplicas, String obsoletes, String obsoletedBy, BigInteger serialVersion)
1071 1076
    {
1072 1077
        DBConnection dbConn = null;
1073 1078
        int serialNumber = -1;
......
1082 1087
            String query = "update " + TYPE_SYSTEM_METADATA + 
1083 1088
                " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
1084 1089
                "origin_member_node, authoritive_member_node, date_modified, " +
1085
                "submitter, object_format, size, replication_allowed, number_replicas, obsoletes, obsoleted_by) " +
1086
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
1090
                "submitter, object_format, size, replication_allowed, number_replicas, " +
1091
                "obsoletes, obsoleted_by, serial_version) " +
1092
                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
1087 1093
            PreparedStatement stmt = dbConn.prepareStatement(query);
1088 1094
            
1089 1095
            //data values
......
1101 1107
            stmt.setInt(12, numberReplicas);
1102 1108
            stmt.setString(13, obsoletes);
1103 1109
            stmt.setString(14, obsoletedBy);
1110
            stmt.setString(15, serialVersion.toString());
1104 1111

  
1105 1112
            //where clause
1106
            stmt.setString(15, guid);
1113
            stmt.setString(16, guid);
1107 1114
            logMetacat.debug("stmt: " + stmt.toString());
1108 1115
            //execute
1109 1116
            int rows = stmt.executeUpdate();
......
1245 1252
				sm.getDateSysMetadataModified() == null ? null: sm.getDateSysMetadataModified().getTime(),
1246 1253
				sm.getSubmitter() == null ? null: sm.getSubmitter().getValue(), 
1247 1254
        sm.getIdentifier().getValue(),
1248
        sm.getFmtid() == null ? null: sm.getFmtid().getValue(),
1255
        sm.getFormatId() == null ? null: sm.getFormatId().getValue(),
1249 1256
        sm.getSize(),
1250 1257
        replicationAllowed, 
1251 1258
        numberReplicas,
1252 1259
        sm.getObsoletes() == null ? null:sm.getObsoletes().getValue(),
1253
        sm.getObsoletedBy() == null ? null: sm.getObsoletedBy().getValue());
1260
        sm.getObsoletedBy() == null ? null: sm.getObsoletedBy().getValue(),
1261
        sm.getSerialVersion()
1262
        );
1254 1263
        
1255 1264
        String guid = sm.getIdentifier().getValue();
1256 1265
        
......
1583 1592
                // set the format type
1584 1593
                ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
1585 1594
            	fmtid.setValue(fmtidStr);
1586
                oi.setFmtid(fmtid);
1595
                oi.setFormatId(fmtid);
1587 1596
                
1588 1597
//                try {
1589 1598
//	                oi.setFmtid(ObjectFormatCache.getInstance().getFormat(fmtidStr).getFmtid());
build.xml
271 271
		<property name="docdir" value="./docs" />
272 272
		<property name="cgidir" value="./cgi-bin" />
273 273
		<property name="testdir" value="./test" />
274
		<property name="testtorun" value="CNodeServiceTest" />
274
		<property name="testtorun" value="InlineDataAccessTest" />
275 275
		<property name="junittestsdir"
276 276
			value="./test/edu/ucsb/nceas/metacattest" />
277 277
		<property name="junitnettestsdir"

Also available in: Unified diff