ピクセルの色


8

画面上の特定のピクセルのRGBカラーを印刷するプログラムを記述します。

プログラムはstdinから行をの形式x,yで読み取る必要があります。ここで、xとyは符号なし整数です。ピクセル(0,0)は、画面の左上のピクセルです。

次に、プログラムは、RRR,GGG,BBBxy)のピクセルの色を表す形式で行をstdoutに出力します。

RRRGGG、及びBBB0と1の間の浮動小数点数でなければならないOR範囲内の整数[0、255]。たとえば、先行ゼロは重要ではありません。両方07474は許容されます。

未定義の動作

次の条件で、プログラムが未定義の動作(クラッシュ、不正な出力など)を示すことは問題ありません。

  • ユーザーが文字列、符号付き整数、浮動小数点数、またはその他の無効なデータ型を入力した
  • ユーザー入力が形式ではありません x,y
  • 指定されたピクセルは画面外です

ノート:

  • プログラムは、指定された座標のピクセルを変更できません。
  • 複数のモニターがある場合、プログラムが実行されるたびに同じモニターが使用される限り、ピクセルがオンになっているモニターは問題ではありません。

バイト数が最も少ない答えが優先されます。


24
なぜなければならないRRRGGGと、BBB0と1の間のポイントを浮動しますか?通常、これらは範囲内の整数です[0,255]。両方を許可することをお勧めします。
Kevin Cruijssen、2018

4
そのウィンドウの外の画面上の何にもアクセスできない言語のために、ソリューションを実行されているウィンドウに制限できますか?
Shaggy

7
あなたが唯一の0許可する場合- 1フォーマットを、あなたは使用しないでくださいRRRGGGBBBスペックではなくRGB
sergiol

6
複数のモニターがある場合はどうなりますか?
tsh

7
プログラムが指定された座標のピクセルを変更できないことを指定することは価値があります。それ以外の場合は、画面全体をブラックアウトしてに戻る方が効率的0, 0, 0であり、チャレンジの目的を無効にします。
maxb

回答:


10

Java 10(ラムダ関数)、105 75バイト

x->y->(new java.awt.Robot().getPixelColor(x,y)+"").replaceAll("[^\\d,]","")

2つの整数パラメータを取り、文字列を返す関数。RRR,GGG,BBB色は範囲内の整数です[0, 255]

@LukeStevensのおかげで-30バイト。java.awt.ColorデフォルトのtoString()出力を使用し、数字とコンマのみが残るように変更しました。

説明:

x->y->                      // Method with two integer parameters and String return-type
  (new java.awt.Robot()     //  Create a AWT-Robot instance
    .getPixelColor(x,y)     //  Get the pixel AWT-Color at position x,y
    +"")                    //  Call the default toString() of the AWT-Color
                            //   i.e. "java.awt.Color[r=213,g=230,b=245]"
  .replaceAll("[^\\d,]","") //  Remove everything except for digits and commas

注:のデフォルトのtoString()実装は、java.awt.Color私の知る限り、JVMのバージョン間で常に同じですが、将来変更される可能性があります。私はJava 8とJava 10の両方でテストしましたが、戻りました"java.awt.Color[r=#,g=#,b=#]"


しかし、挑戦が述べているので:

  • 完全なプログラム
  • x,ySTDINからの形式での入力
  • R,G,BSTDOUTへのフォーマットで出力
  • 持っているRGB範囲内の浮動小数点として[0.0, 1.0]

コードはもっと冗長になります:

Java 10(完全なプログラム)、266バイト

interface M{static void main(String[]a)throws Exception{var s=new java.util.Scanner(System.in).next().split(",");var c=new java.awt.Robot().getPixelColor(new Short(s[0]),new Short(s[1]));System.out.print(c.getRed()/255d+","+c.getGreen()/255d+","+c.getBlue()/255d);}}

説明:

interface M{          // Class
  static void main(String[]a)
                      //  Mandatory main method
    throws Exception{ //    Mandatory throws clause for `new Robot()`
  var s=new java.util.Scanner(System.in)
                      //   Create a Scanner for STDIN
         .next()      //   Get the String user input
         .split(","); //   Split it on "," and save it as String-array in `s`
  var c=new java.awt.Robot()
                      //   Create a AWT-Robot instance
         .getPixelColor(
                      //   And get the pixel AWT-Color at position:
           new Short( //    Convert String to Short (and implicitly to int):
            s[0]),    //     x-coordinate input by user from String-array `s`
           new Short( //    Convert String to Short (and implicitly to int):
            s[1]));   //     y-coordinate input by user from String-array `s`
  System.out.print(   //   Print to STDOUT:
   c.getRed()         //    The red part of RGB as integer in the range [0,255]
    /255d             //     Converted to a floating point in the range [0.0, 1.0]
   +","               //    Appended with a comma delimiter
   +c.getGreen()      //    Appended with the green part of RGB as integer in the range [0,255]
     /255d            //     Converted to a floating point in the range [0.0, 1.0]
   +","               //    Appended with a comma delimiter
   +c.getBlue()       //    Appended with the blue part of RGB as integer in the range [0,255]
     /255d);}}        //     Converted to a floating point in the range [0.0, 1.0]

2
最初に、ルーズルールの答えとして、Colors文字列変換を利用x->y->(new java.awt.Robot().getPixelColor(x,y)+"").replaceAll("[^\\d,]","")して75バイトにすることができます
Luke Stevens

デフォルトの@LukeStevensスマート使用toString()java.awt.Color。ありがとう!
Kevin Cruijssen

よくやったね、あなたは私を倒しました:私もtoString()方法を実装するのに忙しかったです... ;-)すべてを行うためにIDEをダウンロードする必要があったことを除いて:私は今TIOのみを使用します:(
OlivierGrégoireDec

3
Javadocは非常に明確でColor::toStringあり、実装は任意です。そのため、テストに使用されたJVMを指定することをお勧めします(OpenJDKおよびOracle JDKでそのまま機能します)。
OlivierGrégoire2018

1
最後に、あなたは交換する必要があります" "","厳格に遵守するRRR,GGG,BBB形式(ではありませんRRR GGG BBB)。
OlivierGrégoire2018

9

6502マシンコード(C64)、280260バイト

00 C0 A2 00 20 CF FF C9 0D 9D 02 C1 F0 03 E8 D0 F3 20 D2 FF A5 7A 85 FB A5 7B
85 FC A9 01 85 7A A9 C1 85 7B 20 73 00 20 6B A9 A5 14 85 FD A5 15 85 FE 20 73
00 20 6B A9 A5 FB 85 7A A5 FC 85 7B A5 14 4A 4A 4A AA 20 F0 E9 A5 FD 46 FE 6A
4A 4A A8 A5 14 29 07 AA A9 00 38 6A CA 10 FC 85 FE B1 D1 0A 26 FC 0A 26 FC 0A
26 FC 85 FB A5 D2 29 03 09 D8 85 D2 B1 D1 85 02 A9 02 18 2D 18 D0 0A 0A 65 FC
29 0F 09 D0 85 FC A9 33 85 01 A5 FD 29 07 A8 B1 FB A2 37 86 01 25 FE D0 05 AD
21 D0 85 02 A6 D6 20 F0 E9 A5 02 29 0F AA BC D2 C0 20 BC C0 BC E2 C0 20 B7 C0
BC F2 C0 A9 2C 20 D2 FF 98 0A A9 30 90 02 A9 31 20 D2 FF A9 2E 20 D2 FF 98 29
7F 4C D2 FF 30 B0 35 35 36 33 32 39 36 33 38 33 35 37 34 37 30 B0 32 38 32 37
32 39 33 32 34 33 35 B0 34 37 30 B0 32 38 36 33 36 34 32 30 34 33 35 36 39 37

私はこれがはるかに少ないバイト数で可能になると期待していましたが、残念ながら...まあ、私がそれを終えたので、とにかく今それを投稿します。少なくとも、制限的な形式は1つのことを助けました:(stdin現在のデバイスからの入力)と同様のものは、テキストモードのC64にのみ存在します。これは、OSがこのモードしかサポートしていないため、グラフィックチップの他のモードを考慮する必要がないためです。 。

色の値の出力に関する注意:C64グラフィックチップはRGBカラーを使用しませんが、16色の固定パレットを使用して、YUVカラーのビデオ信号を直接生成します。ここでは、「デフォルト」のモニター設定で、コロドールの RGBへの変換の丸められた値を使用しました。

-20バイト:より良い出力ルーチン、カラーチャネルごとに3文字の出力を1 バイトにエンコードします。

コメントについて:VICのマルチカラーキャラクターモードでもストックC64 OSで使用することは理論的には可能ですが、実際に判読できるカスタムフォントは、横幅が4倍の4ピクセルのみである必要があります。完全に不可能というわけではありませんが、ほとんどあり得ません。同様に、拡張カラーモード(または同じ拡張背景モード)をC64 OSで使用できますが、グラフィックチップを直接再構成する必要があります。ここでは、コードゴルフという意味でこれらすべての可能性を無視することを選択します。これは、ストックOSを実​​行しているCommodore 64で見られる標準環境ではありません。ストックOSで可能なことは、2つの組み込みフォント(Shift + Commodoreキー)を切り替えることです。プログラムはそれを考慮します。

オンラインデモ

使用法:SYS49152開始します。

コメント付きの分解

         00 C0       .WORD $C000        ; load address
.C:c000  A2 00       LDX #$00           ; loop index for input
.C:c002   .input:
.C:c002  20 CF FF    JSR $FFCF          ; character from input device
.C:c005  C9 0D       CMP #$0D           ; compare with enter
.C:c007  9D 16 C1    STA .buf,X         ; store to buffer
.C:c00a  F0 03       BEQ .parse         ; was enter -> start parsing
.C:c00c  E8          INX                ; next character
.C:c00d  D0 F3       BNE .input         ; and repeat input loop
.C:c00f   .parse:
.C:c00f  20 D2 FF    JSR $FFD2          ; output the enter character
.C:c012  A5 7A       LDA $7A            ; save pointer of BASIC parser
.C:c014  85 FB       STA $FB
.C:c016  A5 7B       LDA $7B
.C:c018  85 FC       STA $FC
.C:c01a  A9 15       LDA #$15           ; set pointer of BASIC parser to
.C:c01c  85 7A       STA $7A            ; buffer-1
.C:c01e  A9 C1       LDA #$C1
.C:c020  85 7B       STA $7B
.C:c022  20 73 00    JSR $0073          ; get next character
.C:c025  20 6B A9    JSR $A96B          ; BASIC routine to parse number
.C:c028  A5 14       LDA $14            ; lowbyte of parsed number to $fd
.C:c02a  85 FD       STA $FD
.C:c02c  A5 15       LDA $15            ; highbyte to $fe
.C:c02e  85 FE       STA $FE
.C:c030  20 73 00    JSR $0073          ; get next character
.C:c033  20 6B A9    JSR $A96B          ; parse as number ...
.C:c036  A5 FB       LDA $FB            ; restore pointer of BASIC parser
.C:c038  85 7A       STA $7A
.C:c03a  A5 FC       LDA $FC
.C:c03c  85 7B       STA $7B
.C:c03e  A5 14       LDA $14            ; load y coordinate
.C:c040  4A          LSR A              ; divide by 8 for character row
.C:c041  4A          LSR A
.C:c042  4A          LSR A
.C:c043  AA          TAX                ; -> to X
.C:c044  20 F0 E9    JSR $E9F0          ; set pointer to character row
.C:c047  A5 FD       LDA $FD            ; divide x coordinate by 8
.C:c049  46 FE       LSR $FE
.C:c04b  6A          ROR A
.C:c04c  4A          LSR A
.C:c04d  4A          LSR A
.C:c04e  A8          TAY                ; -> to Y
.C:c04f  A5 14       LDA $14            ; load y coordinate
.C:c051  29 07       AND #$07           ; mask pixel position in character
.C:c053  AA          TAX                ; -> to X
.C:c054  A9 00       LDA #$00           ; initialize pixel mask to 0
.C:c056  38          SEC                ; set carry for bit to shift in
.C:c057   .bitnum:
.C:c057  6A          ROR A              ; shift bit in mask
.C:c058  CA          DEX                ; and repeat until
.C:c059  10 FC       BPL .bitnum        ; in correct position
.C:c05b  85 FE       STA $FE            ; store pixel mask to $fe
.C:c05d  B1 D1       LDA ($D1),Y        ; load character code
.C:c05f  0A          ASL A              ; multiply by 8
.C:c060  26 FC       ROL $FC
.C:c062  0A          ASL A
.C:c063  26 FC       ROL $FC
.C:c065  0A          ASL A
.C:c066  26 FC       ROL $FC
.C:c068  85 FB       STA $FB            ; and store to $fb/$fc
.C:c06a  A5 D2       LDA $D2            ; move pointer to position in color RAM
.C:c06c  29 03       AND #$03
.C:c06e  09 D8       ORA #$D8
.C:c070  85 D2       STA $D2
.C:c072  B1 D1       LDA ($D1),Y        ; load color of character
.C:c074  85 02       STA $02            ; and store to $2
.C:c076  A9 02       LDA #$02           ; check which charset is active
.C:c078  18          CLC
.C:c079  2D 18 D0    AND $D018
.C:c07c  0A          ASL A              ; and calculate offset
.C:c07d  0A          ASL A
.C:c07e  65 FC       ADC $FC            ; add to (character code * 8)
.C:c080  29 0F       AND #$0F
.C:c082  09 D0       ORA #$D0           ; and add offset to character ROM
.C:c084  85 FC       STA $FC
.C:c086  A9 33       LDA #$33           ; bank in character ROM
.C:c088  85 01       STA $01
.C:c08a  A5 FD       LDA $FD            ; load y coordinate
.C:c08c  29 07       AND #$07           ; mask pixel-row number
.C:c08e  A8          TAY
.C:c08f  B1 FB       LDA ($FB),Y        ; load pixel row from character ROM
.C:c091  A2 37       LDX #$37           ; bank out character ROM
.C:c093  86 01       STX $01
.C:c095  25 FE       AND $FE            ; apply pixel mask
.C:c097  D0 05       BNE .pixelcol      ; not 0 -> pixel is set
.C:c099  AD 21 D0    LDA $D021          ; otherwise load background color
.C:c09c  85 02       STA $02            ; and store to $2
.C:c09e   .pixelcol:
.C:c09e  A6 D6       LDX $D6            ; restore screen row pointer for
.C:c0a0  20 F0 E9    JSR $E9F0          ; current cursor position
.C:c0a3  A5 02       LDA $02            ; load color
.C:c0a5  29 0F       AND #$0F           ; mask low nibble (only 16 colors)
.C:c0a7  AA          TAX                ; -> to X
.C:c0a8  BC D2 C0    LDY .red,X         ; load encoded output for red
.C:c0ab  20 BC C0    JSR .out2          ; call output without comma
.C:c0ae  BC E2 C0    LDY .green,X       ; load encoded output for green
.C:c0b1  20 B7 C0    JSR .out1          ; call output with comma
.C:c0b4  BC F2 C0    LDY .blue,X        ; load encoded output for blue
.C:c0b7   .out1:
.C:c0b7  A9 2C       LDA #$2C           ; load ","
.C:c0b9  20 D2 FF    JSR $FFD2          ; and output
.C:c0bc   .out2:
.C:c0bc  98          TYA                ; encoded output to A
.C:c0bd  0A          ASL A              ; shift top bit to carry
.C:c0be  A9 30       LDA #$30           ; load "0"
.C:c0c0  90 02       BCC .firstdig      ; carry clear -> to output
.C:c0c2  A9 31       LDA #$31           ; load "1"
.C:c0c4   .firstdig:
.C:c0c4  20 D2 FF    JSR $FFD2          ; and output
.C:c0c7  A9 2E       LDA #$2E           ; load "."
.C:c0c9  20 D2 FF    JSR $FFD2          ; and output
.C:c0cc  98          TYA                ; encoded output to A
.C:c0cd  29 7F       AND #$7F           ; mask out top bit
.C:c0cf  4C D2 FF    JMP $FFD2          ; to output and exit
.C:c0d2   .red:                                 ; encoded values for red
.C:c0d2  30 B0 35 35 .BYTE $30,$B0,$35,$35      ; ASCII digit ($30-$39) after
.C:c0d6  36 33 32 39 .BYTE $36,$33,$32,$39      ; decimal point, with bit 7
.C:c0da  36 33 38 33 .BYTE $36,$33,$38,$33      ; indicating 0 or 1 before
.C:c0de  35 37 34 37 .BYTE $35,$37,$34,$37      ; decimal point
.C:c0e2   .green:                               ; encoded values for green
.C:c0e2  30 B0 32 38 .BYTE $30,$B0,$32,$38      ; ...
.C:c0e6  32 37 32 39 .BYTE $32,$37,$32,$39
.C:c0ea  33 32 34 33 .BYTE $33,$32,$34,$33
.C:c0ee  35 B0 34 37 .BYTE $35,$B0,$34,$37
.C:c0f2   .blue:                                ; encoded values for blue
.C:c0f2  30 B0 32 38 .BYTE $30,$B0,$32,$38      ; ...
.C:c0f6  36 33 36 34 .BYTE $36,$33,$36,$34
.C:c0fa  32 30 34 33 .BYTE $32,$30,$34,$33
.C:c0fe  35 36 39 37 .BYTE $35,$36,$39,$37
.C:c102   .buf:                                 ; buffer for input ("stdin")

これはマルチカラーモードをサポートしていないようです
nwellnhof 2018

もちろん、元のOSでは動作しません。技術的には、このOSはどのVICモードでも動作しますが、画面にはゴミしか表示されないため、使用できません。しかし、あなたのコメントは私に「拡張カラーモード」を覚えさせました、それは標準のOSでかなりうまくいきます... dammit
Felix Palmen

@nwellnhofはそれについていくつかの推論を追加しました、これが同意できることを願っています。
Felix Palmen、

これをCで書く方が短いかどうか疑問に思いますか?

@Rogemはそれをcc65..可能性のある方法で試すことができますが、少なくとも、コンパイルされたコード大きくなります:)
Felix Palmen

6

TI-BASIC(TI-83 / 84 +)、22バイト

画面は白黒なので、指定したピクセルがオンかオフかをテストし、それを黒または白のRGBにマッピングするだけです。また、ピクセルには行と列の順序でのみアクセスできるため、座標が逆になります。

Prompt X,Y
255
Ans-{Ans,Ans,Ans}pxl-Test(Y,X

1
これは(TI-84 Plus CEのような)カラーTI計算機では機能しないことに注意してください。
pizzapants184

バイトカウントについて確信がありますか?私は22を数える
lirtosiast

2

bash、103/86バイト

仕様を厳密に解釈すると(STDINからの入力とSTDOUTでの出力は両方ともカンマで区切られます):

read x
import -window root -crop 1x1+${x/,/+} ppm:-|od -dj13|awk 'NR<2{n=2^16;print$2/n","$3/n","$4/n}'

より緩やかな入力形式(コマンドライン引数としてのプラス区切りの入力、スペース区切りの出力:

import -window root -crop 1x1+$1 ppm:-|od -dj13|awk 'NR<2{n=2^16;print$2/n,$3/n,$4/n}'

imagemagick、awk、およびcoreutilsに依存します。


2

TI-Nspireアセンブリ-112バイト

50 52 47 00 30 40 2D E9 FF FF FF FA 00 F0 17 F8
04 1C 00 F0 14 F8 85 00 2D 18 AD 01 2D 19 6C 00
C0 21 09 06 09 69 08 5B 3F 25 42 09 2A 40 1F 25
03 1C 2B 40 C1 0A 29 40 0A A0 0A DF 30 BD 00 20
0A 23 07 49 10 25 8A 69 2A 42 FC D1 0A 68 FF 25
2A 40 30 3A 0B DB 85 00 2D 18 6D 00 A8 18 F1 E7
00 00 02 90 25 64 2C 25 64 2C 25 64 0A 00 70 47

このプログラムは、デバイスがネイティブにRGB565フレームバッファを使用するため、RおよびBの場合は0〜31、Gの場合は0〜63の範囲の整数を出力します。入力と出力にシリアルを使用します。

ソース:

.string "PRG"
push {r4, r5, lr}
blx main
.thumb
main:
@ read x and y from serial into r4 and r0
bl read_int
mov r4, r0
bl read_int

@ turn x and y into framebuffer offset
@ r4 = ((r0 * 320) + r4) * 2
lsl r5, r0, #2
add r5, r0
lsl r5, #6
add r5, r4
lsl r4, r5, #1

@ load pixel from framebuffer
@ r0 = ((uint16_t **)0xc0000000)[0x10][r4 / 2]
mov r1, #0xC0
lsl r1, #24
ldr r1, [r1, #0x10]
ldrh r0, [r1, r4]

@ unpack RGB565 value into r1, r2, r3
mov r5, #0x3f
lsr r2, r0, #5
and r2, r5
mov r5, #0x1f
mov r3, r0
and r3, r5
lsr r1, r0, #11
and r1, r5

@ call printf
adr r0, fmt
swi #10

@ return
pop {r4, r5, pc}

@ subroutine to read an integer from serial
read_int:
mov r0, #0
mov r3, #10
ldr r1, serial_base
@ loop until characters come in on serial
2:
mov r5, #(1<<4) 
1:
ldr r2, [r1, #0x18]
tst r2, r5
bne 1b
@ read character from serial and mask out status bits
ldr r2, [r1]
mov r5, #0xff
and r2, r5
@ subtract 48 ('0') from byte; if result is negative, return
sub r2, #48
blt 1f
@ multiply existing numbers by 10 and add new number to them
lsl r5, r0, #2
add r5, r0
lsl r5, #1
add r0, r5, r2
b 2b

serial_base:.word 0x90020000
fmt:.string "%d,%d,%d\n"
@ this instruction is over here because serial_base and fmt need to be word-aligned
1:bx lr

2

xserverを使用するLinuxのBash、30バイト

xset dpms force off;echo 0,0,0

質問に対する私のコメントで提示されたアイデアを使用すると、このソリューションはディスプレイ出力を完全にオフにし、画面が実際に真っ黒であることをエコーする必要があります。

を使用することも考えxbacklight =0ていましたが、ピクセルの色は変わりません。


抜け穴を見つけるための+1ですが、制約を更新しました。
18

1

Python 2 + PILライブラリ、96 91バイト

import PIL.ImageGrab as i
print','.join('%.1f'%(x/255.)for x in i.grab().getpixel(input()))

要求どおりに文字通り仕様を実装します。ただし、Windowsのみ-Linuxでは機能せず、Macでは追加の出力(アルファ値)を生成します。


from PIL import ImageGrab as ifrom PIL import*i.grabImageGrab.grab
Erik the Outgolfer 2018

@ErikこれはPILではありません。PILは明示的にリストされた名前のみをインポートします。
OVS

@ovs、ああ、それがおそらく私が__import__('...')方法を機能させることができなかった問題です
キリルL.

これはmacOSではアルファ値を出力するため、Windowsの仕様にのみ準拠していることに注意してください。
2018

@ovs、わかりました。知っておくと便利です。ありがとう。
Kirill L.

1

Mathematica、69バイト

ただの機能は34バイトです。

CurrentScreenImage[]~PixelValue~#&

{x、y}の形式で入力を受け取ります。

画像は、すべてのモニターの画像をマージしたものです。特定の画面が必要な場合は、整数インデックスを使用してください-例 CurrentScreenImage[1]

指定されたとおりの完全なプログラムは69バイト CurrentScreenImage[]~PixelValue~ToExpression["{"<>InputString[]<>"}"]



0

Bash + coreutils + scrot + netpbm、90バイト

scrot -e'pngtopnm $f'|(read a;read w h;read m;head -c$((3*(w*$2+$1)))>f;od -t u1 -N3 -An;)

I / Oバージョンが緩い

xおよびyを個別のコマンドライン引数として受け取ります。

プリントrgb別の行に0-255からint値として


Bash + coreutils + scrot + netpbm + bc + sed、172バイト

IFS=, read x y
scrot -e'pngtopnm $f'|(read a;read w h;read m;head -c$((3*(w*$y+$x)))>f;od -vw1 -tu1 -N3 -An|while read p;do bc<<<"scale=2;$p/$m"|tr '\n' ,;done;)|sed s/,$//

厳格なI / Oバージョン

stdinとしての入力 x,y

stdoutにr.rr,g.gg,b.bb(改行なし)として出力します。


@Shaggyはもうありません-更新を参照してください
eeze

0

TI-BASIC(TI-83 / 84 +)、15バイト

Input Y
255not(rand(3)pxl-Test(Y,Ans

Ansプロンプトから整数を1つとプロンプトから1つを取得します。rand(3)ゼロでない3つの乱数のリストを作成するため、ピクセルが暗い場合、積はゼロになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.