{"id":865,"date":"2021-09-15T13:13:15","date_gmt":"2021-09-15T17:13:15","guid":{"rendered":"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/?p=865"},"modified":"2021-09-15T14:50:07","modified_gmt":"2021-09-15T18:50:07","slug":"sapeck-lineexercises","status":"publish","type":"post","link":"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/sapeck\/09\/15\/sapeck-lineexercises\/","title":{"rendered":"sapeck-LineExercises"},"content":{"rendered":"<h3>A: Dashed Line<\/h3>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-866\" src=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/2021\/09\/sapeck_03_A_DashedLine_0128.png\" alt=\"\" width=\"640\" height=\"480\" \/><\/p>\n<pre>\/*\r\n* sapeck_03_A_DashedLine.pde\r\n* A dashed line between the center and the mouse\r\n* Originally created by sapeck 2021-09-14\r\n* CMU 60-428 F21 Drawing With Machines\r\n*\/\r\n\r\nint DASH_INTERVAL = 20;\r\n\r\nvoid setup() {\r\n  size(640, 480);\r\n}\r\n\r\nvoid draw() {\r\n  background(255, 255, 255);\r\n  \r\n  \r\n  float d = dist(width\/2, height\/2, mouseX, mouseY);\r\n  float num = d\/DASH_INTERVAL;\r\n  for (int i = 0; i &lt;= num; i += 2) {\r\n    float x1 = lerp(width\/2, mouseX, i\/num);\r\n    float y1 = lerp(height\/2, mouseY, i\/num);\r\n    float x2 = lerp(width\/2, mouseX, min(1.0, (i+1)\/num));\r\n    float y2 = lerp(height\/2, mouseY, min(1.0, (i+1)\/num));\r\n    line(x1, y1, x2, y2);\r\n  }\r\n}\r\n\r\nvoid mouseClicked() {\r\n  saveFrame(\"sapeck_03_A_DashedLine_####.png\");\r\n}\r\n<\/pre>\n<h3>B: Living Line<\/h3>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-869\" src=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/2021\/09\/sapeck_03_B_LivingLine_0429.png\" alt=\"\" width=\"640\" height=\"480\" \/><\/p>\n<pre>\/*\r\n* sapeck_03_B_LivingLine.pde\r\n* A mouse trail\r\n* Originally created by sapeck 2021-09-14\r\n* CMU 60-428 F21 Drawing With Machines\r\n*\/\r\n\r\nint NUM_POSITIONS = 100;\r\n\r\n\/\/ Two 2D arrays\r\nArrayList x_positions = new ArrayList();\r\nArrayList y_positions = new ArrayList();\r\n\r\n\/\/ One 2D Array\r\nArrayList&lt;Integer[]&gt; xy_positions = new ArrayList&lt;Integer[]&gt;();\r\n\r\n\/\/ One Array of Objects (PVectors)\r\nArrayList pv_positions = new ArrayList();\r\n\r\nvoid setup() {\r\n  size(640, 480);\r\n}\r\n\r\nvoid mouseMoved() {\r\n  \/\/ If there are 100 points recorded, remove the first one\r\n  \/\/ This is a FIFO list, so the items are appended to the end\r\n  \/\/ and removed from the beginning.\r\n  if (x_positions.size() &gt;= 100) {\r\n    x_positions.remove(0);\r\n    y_positions.remove(0);\r\n    xy_positions.remove(0);\r\n    pv_positions.remove(0);\r\n  }\r\n  \r\n  \/\/ Add the new location\r\n  x_positions.add(mouseX);\r\n  y_positions.add(mouseY);\r\n  Integer[] xy = { mouseX, mouseY };\r\n  xy_positions.add(xy);\r\n  PVector pv = new PVector(mouseX, mouseY);\r\n  pv_positions.add(pv);\r\n}\r\n\r\nvoid draw() {\r\n  background(255, 255, 255);\r\n  \r\n  beginShape();\r\n  for (int i = 0; i &lt; pv_positions.size(); i++) {\r\n    \/\/ Loop over each item in the list and add a point\r\n    \/\/ to the line\r\n    PVector pv = pv_positions.get(i);\r\n    vertex(pv.x, pv.y);\r\n  }\r\n  endShape();\r\n}\r\n\r\nvoid mouseClicked() {\r\n  saveFrame(\"sapeck_03_B_LivingLine_####.png\");\r\n}\r\n<\/pre>\n<h3>C: Spicy Line<\/h3>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-870\" src=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/2021\/09\/sapeck_03_C_SpicyLine_0354.png\" alt=\"\" width=\"640\" height=\"480\" \/><\/p>\n<pre>\/*\r\n* sapeck_03_C_SpicyLine.pde\r\n* A mouse trail that gets spicy\r\n* Originally created by sapeck 2021-09-14\r\n* CMU 60-428 F21 Drawing With Machines\r\n*\/\r\n\r\nint NUM_POSITIONS = 100;\r\nfloat RANDOMNESS_START = 1;\r\nfloat RANDOMNESS_RATE = 0.008;\r\n\r\n\/\/ One Array of Objects (PVectors)\r\nArrayList pv_positions = new ArrayList();\r\n\r\nfloat randomness = RANDOMNESS_START;\r\n\r\nvoid setup() {\r\n  size(640, 480);\r\n}\r\n\r\nvoid mouseMoved() {\r\n  \/\/ Increase the randomness over time of movements\r\n  randomness += RANDOMNESS_RATE;\r\n  \r\n  \/\/ If there are 100 points recorded, remove the first one\r\n  \/\/ This is a FIFO list, so the items are appended to the end\r\n  \/\/ and removed from the beginning.\r\n  if (pv_positions.size() &gt;= 100) pv_positions.remove(0);\r\n  \r\n  \/\/ Add the new location\r\n  float x = mouseX + random(-1 * randomness, randomness);\r\n  float y = mouseY + random(-1 * randomness, randomness);\r\n  PVector pv = new PVector(x, y);\r\n  pv_positions.add(pv);\r\n}\r\n\r\nvoid draw() {\r\n  background(255, 255, 255);\r\n  \r\n  beginShape();\r\n  for (int i = 0; i &lt; pv_positions.size(); i++) {\r\n    \/\/ Loop over each item in the list and add a point\r\n    \/\/ to the curve\r\n    PVector pv = pv_positions.get(i);\r\n    vertex(pv.x, pv.y);\r\n  }\r\n  endShape();\r\n}\r\n\r\nvoid mouseClicked() {\r\n  saveFrame(\"sapeck_03_C_SpicyLine_####.png\");\r\n}\r\n<\/pre>\n<h3>D: One Circle, Two Ways<\/h3>\n<h4>Sine and Cosine Points<\/h4>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-873\" src=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/2021\/09\/sapeck_03_D_OneCircleTwoWays_SINCOSPoints_0051.png\" alt=\"\" width=\"640\" height=\"480\" \/><\/p>\n<pre>\/*\r\n* sapeck_03_D_OneCircleTwoWays_SINCOSPoints.pde\r\n* A circle made from sine and cosine points\r\n* Originally created by sapeck 2021-09-14\r\n* CMU 60-428 F21 Drawing With Machines\r\n*\/\r\n\r\nint NUM_POINTS = 20;\r\nfloat CIRCLE_RADIUS = 100;\r\n\r\n\/\/ One Array of Objects (PVectors)\r\nPVector pv_positions[] = new PVector[NUM_POINTS];\r\n\r\nvoid setup() {\r\n  size(640, 480);\r\n  \r\n  for (int i = 0; i &lt; NUM_POINTS; i++) {\r\n    float x = CIRCLE_RADIUS * cos(i * (TWO_PI \/ NUM_POINTS)) + (width \/ 2); \r\n    float y = CIRCLE_RADIUS * sin(i * (TWO_PI \/ NUM_POINTS)) + (height \/ 2); \r\n    pv_positions[i] = new PVector(x, y);\r\n  }\r\n}\r\n\r\nvoid draw() {\r\n  background(255, 255, 255);\r\n  \r\n  beginShape();\r\n  for (int i = 0; i &lt; NUM_POINTS; i++) {\r\n    \/\/ Loop over each item in the list and add a point\r\n    \/\/ to the curve\r\n    PVector pv = pv_positions[i];\r\n    vertex(pv.x, pv.y);\r\n  }\r\n  endShape(CLOSE);\r\n}\r\n\r\nvoid mouseClicked() {\r\n  saveFrame(\"sapeck_03_D_OneCircleTwoWays_SINCOSPoints_####.png\");\r\n}\r\n<\/pre>\n<h4>Cosine and Square Root<\/h4>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-880\" src=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/2021\/09\/sapeck_03_D_OneCircleTwoWays_SQRT_0064.png\" alt=\"\" width=\"640\" height=\"480\" \/><\/p>\n<pre>\/*\r\n* sapeck_03_D_OneCircleTwoWays_SQRT.pde\r\n* A circle made from cosine and square root\r\n* Originally created by sapeck 2021-09-14\r\n* CMU 60-428 F21 Drawing With Machines\r\n*\/\r\n\r\nint NUM_POINTS = 20;\r\nfloat CIRCLE_RADIUS = 100;\r\n\r\n\/\/ One Array of Objects (PVectors)\r\nPVector pv_positions[] = new PVector[NUM_POINTS];\r\n\r\nfloat CIRCLE_RADIUS_SQ = pow(CIRCLE_RADIUS, 2);\r\n\r\nvoid setup() {\r\n  size(640, 480);\r\n  \r\n  for (int i = 0; i &lt; NUM_POINTS; i++) { float x = CIRCLE_RADIUS * cos(i * (TWO_PI \/ NUM_POINTS)); float x_sq = pow(x, 2); float y = sqrt(CIRCLE_RADIUS_SQ - x_sq); float x_aligned = x + (width \/ 2); float y_aligned = (height \/ 2) + y; if (i &gt; NUM_POINTS \/ 2) y_aligned -= 2 * y;\r\n    pv_positions[i] = new PVector(x_aligned, y_aligned);\r\n  }\r\n}\r\n\r\nvoid draw() {\r\n  background(255, 255, 255);\r\n  \r\n  beginShape();\r\n  for (int i = 0; i &lt; NUM_POINTS; i++) {\r\n    \/\/ Loop over each item in the list and add a point\r\n    \/\/ to the curve\r\n    PVector pv = pv_positions[i];\r\n    vertex(pv.x, pv.y);\r\n  }\r\n  endShape(CLOSE);\r\n}\r\n\r\nvoid mouseClicked() {\r\n  saveFrame(\"sapeck_03_D_OneCircleTwoWays_SQRT_####.png\");\r\n}\r\n<\/pre>\n<h3>E: Spiral<\/h3>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-882\" src=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/2021\/09\/sapeck_03_E_Spiral_0028.png\" alt=\"\" width=\"640\" height=\"480\" \/><\/p>\n<pre>\/*\r\n* sapeck_03_E_Spiral.pde\r\n* A spiral made from a circle with increasing radius\r\n* Originally created by sapeck 2021-09-14\r\n* CMU 60-428 F21 Drawing With Machines\r\n*\/\r\n\r\nint POINTS_PER_ROTATION = 10;\r\nint NUM_POINTS = 50;\r\nfloat RADIUS_GROWTH_PER_POINT = 4;\r\n\r\n\/\/ One Array of Objects (PVectors)\r\nPVector pv_positions[] = new PVector[NUM_POINTS];\r\n\r\nfloat radius = 0;\r\n\r\nvoid setup() {\r\n  size(640, 480);\r\n  \r\n  for (int i = 0; i &lt; NUM_POINTS; i++) {\r\n    float theta = i * (TWO_PI \/ POINTS_PER_ROTATION);\r\n    float x = radius * cos(theta) + (width \/ 2);\r\n    float y = radius * sin(theta) + (height \/ 2);\r\n    pv_positions[i] = new PVector(x, y);\r\n    radius += RADIUS_GROWTH_PER_POINT;\r\n  }\r\n}\r\n\r\nvoid draw() {\r\n  background(255, 255, 255);\r\n  \r\n  beginShape();\r\n  for (int i = 0; i &lt; NUM_POINTS; i++) {\r\n    \/\/ Loop over each item in the list and add a point\r\n    \/\/ to the curve\r\n    PVector pv = pv_positions[i];\r\n    curveVertex(pv.x, pv.y);\r\n  }\r\n  endShape();\r\n}\r\n\r\nvoid mouseClicked() {\r\n  saveFrame(\"sapeck_03_E_Spiral_####.png\");\r\n}\r\n<\/pre>\n<h3>F: Parallel Polyline<\/h3>\n<p>For this one, I used vsketch, vpype, and shapely. It&#8217;s as simple as installing these Python packages and then running &#8220;vsk run&#8221; and it will bring a viewer, auto-reload your code, and save an SVG for you when you click the &#8220;LIKE!&#8221;button.<img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-medium wp-image-884\" src=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/2021\/09\/sapeck_03_f_parallelpolyline_vsk_liked_1.svg\" alt=\"\" width=\"640\" height=\"480\" \/><\/p>\n<pre>#!\/usr\/bin\/env python3\r\n#\r\n# sapeck_03_F_ParallelPolyline.py\r\n# Draw a teardrop-like shape with inner and outer offset lines\r\n# Originally created by sapeck 2021-09-15\r\n# CMU 60-428 F21 Drawing With Machines\r\n#\r\n\r\nfrom math import cos, sin\r\n\r\nfrom shapely.geometry import LineString, MultiLineString\r\nimport vsketch\r\n\r\nPI = 3.14159\r\n\r\nclass Sapeck03FParallelpolylineVskSketch(vsketch.SketchClass):\r\n    CIRCLE_POINTS = 100\r\n    RADIUS = 2\r\n\r\n    def draw(self, vsk: vsketch.Vsketch) -&gt; None:\r\n        vsk.size(\"letter\", landscape=False)\r\n        vsk.scale(\"in\")\r\n\r\n        # This makes a teardrop-like shape\r\n        points = [(0, 0)]\r\n        for i in range(0, self.CIRCLE_POINTS):\r\n          x = self.RADIUS * cos(i * (PI \/ self.CIRCLE_POINTS))\r\n          y = self.RADIUS * sin(i * (PI \/ self.CIRCLE_POINTS)) + self.RADIUS + 1\r\n          points.append((x, y))\r\n        points.append((0, 0))\r\n        \r\n        # points is just an array of (x, y) points\r\n        line = LineString(points)\r\n        vsk.stroke(1)\r\n        vsk.geometry(line)\r\n        \r\n        # Now make the inner and outer offsets\r\n        vsk.stroke(2)\r\n        offset0 = line.parallel_offset(1, 'left',  join_style=2, mitre_limit=10.0) # inner offset\r\n        offset1 = line.parallel_offset(1, 'right', join_style=2, mitre_limit=10.0) # outer offset\r\n        vsk.geometry(offset0)\r\n        vsk.geometry(offset1)\r\n\r\n    def finalize(self, vsk: vsketch.Vsketch) -&gt; None:\r\n        # We can automatically apply vpype settings here too!\r\n        vsk.vpype(\"linemerge linesimplify reloop linesort\")\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    Sapeck03FParallelpolylineVskSketch.display()\r\n\r\n<\/pre>\n<h3>G: Lines of Different Weights<\/h3>\n<p><a href=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/2021\/09\/sapeck_03_g_linesofdifferentweights_liked_3.svg\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-medium wp-image-899\" src=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/2021\/09\/sapeck_03_g_linesofdifferentweights_liked_3.svg\" alt=\"\" width=\"640\" height=\"480\" \/><\/a><\/p>\n<pre>#!\/usr\/bin\/env python3\r\n#\r\n# sapeck_03_G_LinesOfDifferentWeights.py\r\n# Draw different weight lines using offset curves\r\n# Originally created by sapeck 2021-09-15\r\n# CMU 60-428 F21 Drawing With Machines\r\n#\r\n\r\nfrom math import cos, sin\r\n\r\nfrom shapely.geometry import LineString, MultiLineString\r\nimport vsketch\r\n\r\nPI = 3.14159\r\n\r\nclass Sapeck03GLinesofdifferentweightsSketch(vsketch.SketchClass):\r\n    CIRCLE_POINTS = 100\r\n    RADIUS = 2\r\n    OFFSET_AMOUNT = 0.0025\r\n    OFFSET_NUM = 10\r\n\r\n    def draw(self, vsk: vsketch.Vsketch) -&gt; None:\r\n        vsk.size(\"letter\", landscape=False)\r\n        vsk.scale(\"in\")\r\n\r\n        # This makes a teardrop-like shape\r\n        points = [(0, 0)]\r\n        for i in range(0, self.CIRCLE_POINTS):\r\n          x = self.RADIUS * cos(i * (PI \/ self.CIRCLE_POINTS))\r\n          y = self.RADIUS * sin(i * (PI \/ self.CIRCLE_POINTS)) + self.RADIUS + 1\r\n          points.append((x, y))\r\n        points.append((0, 0))\r\n        \r\n        # points is just an array of (x, y) points\r\n        line = LineString(points)\r\n        vsk.stroke(1)\r\n        vsk.geometry(line)\r\n        \r\n        # Now make the inner offsets\r\n        vsk.stroke(2)\r\n        for i in range(0, self.OFFSET_NUM):\r\n          offset = line.parallel_offset(i * self.OFFSET_AMOUNT, 'left',  join_style=2, mitre_limit=10.0) # inner offset\r\n          vsk.geometry(offset)\r\n\r\n    def finalize(self, vsk: vsketch.Vsketch) -&gt; None:\r\n        vsk.vpype(\"linemerge linesimplify reloop linesort\")\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    Sapeck03GLinesofdifferentweightsSketch.display()\r\n<\/pre>\n<h3>H: Calligraphic Polyline<\/h3>\n<p><a href=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/2021\/09\/sapeck_03_h_calligraphicpolyline_liked_1.svg\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-medium wp-image-963\" src=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/2021\/09\/sapeck_03_h_calligraphicpolyline_liked_1.svg\" alt=\"\" width=\"640\" height=\"480\" srcset=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/\/2021\/09\/sapeck_03_h_calligraphicpolyline_liked_1.svg 640w, https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-content\/uploads\/\/2021\/09\/sapeck_03_h_calligraphicpolyline_liked_1.svg 27w\" sizes=\"(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><\/a><\/p>\n<pre>#!\/usr\/bin\/env python3\r\n#\r\n# sapeck_03_H_CalligraphicPolyline.py\r\n# Draw a calligraphic sine wave\r\n# Originally created by sapeck 2021-09-15\r\n# CMU 60-428 F21 Drawing With Machines\r\n#\r\n\r\nfrom math import cos, dist, sin\r\n\r\nimport numpy as np\r\nfrom shapely.geometry import LineString, MultiLineString, Point\r\nfrom shapely.ops import unary_union\r\nimport vsketch\r\n\r\nPI = 3.14159\r\n\r\nclass Sapeck03HCalligraphicpolylineSketch(vsketch.SketchClass):\r\n    CIRCLE_POINTS = 1000\r\n    RADIUS = 3\r\n    #OFFSET_AMOUNT = 0.0025\r\n    OFFSET_AMOUNT = 0.0025\r\n    OFFSET_MULTIPLIER = 600\r\n    BLEED_OVER = 1\r\n\r\n    def draw(self, vsk: vsketch.Vsketch) -&gt; None:\r\n        vsk.size(\"letter\", landscape=True)\r\n        vsk.scale(\"in\")\r\n\r\n        # This makes a teardrop-like shape\r\n        points = []\r\n        for i in range(0, self.CIRCLE_POINTS):\r\n          x = i * (2 * PI \/ self.CIRCLE_POINTS)\r\n          y = self.RADIUS * sin(x)\r\n          points.append((x, y))\r\n        \r\n        last = None\r\n        for point_i in range(0, len(points) - 1):\r\n          prev_point = points[len(points) - 1] if point_i == 0 else points[point_i - 1]\r\n          point = points[point_i]\r\n          next_point = points[0] if point_i == len(points) - 1 else points[point_i + 1]\r\n          change = dist(point, next_point)\r\n          if change == 0:\r\n            continue\r\n          weight = 1 \/ (change * self.OFFSET_MULTIPLIER) # width of line\r\n          num_lines = int(change \/ self.OFFSET_AMOUNT)\r\n          orig = LineString([point, next_point])\r\n          for i in range(1, num_lines + self.BLEED_OVER):\r\n            next_point_shortened = orig.interpolate(i \/ num_lines, normalized=True)\r\n            orig_short = LineString([Point(point[0], point[1]), next_point_shortened])\r\n            # find perpendicular https:\/\/stackoverflow.com\/a\/57072678\r\n            left = orig_short.parallel_offset(weight \/ 2, 'left')\r\n            right = orig_short.parallel_offset(weight \/ 2, 'right')\r\n            c = left.boundary[1]\r\n            d = right.boundary[0]  # note the different orientation for right offset\r\n            last = d\r\n            vsk.geometry(LineString([c, d]))\r\n          \r\n          \r\n\r\n    def finalize(self, vsk: vsketch.Vsketch) -&gt; None:\r\n        vsk.vpype(\"linemerge linesimplify reloop linesort\")\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    Sapeck03HCalligraphicpolylineSketch.display()\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>A: Dashed Line \/* * sapeck_03_A_DashedLine.pde * A dashed line between the center and the mouse * Originally created by sapeck 2021-09-14 * CMU 60-428 F21 Drawing With Machines *\/ int DASH_INTERVAL = 20; void setup() { size(640, 480); } void draw() { background(255, 255, 255); float d = dist(width\/2, height\/2, mouseX, mouseY); float num &hellip; <a href=\"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/sapeck\/09\/15\/sapeck-lineexercises\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;sapeck-LineExercises&#8221;<\/span><\/a><\/p>\n","protected":false},"author":15,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[10],"tags":[],"_links":{"self":[{"href":"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-json\/wp\/v2\/posts\/865"}],"collection":[{"href":"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-json\/wp\/v2\/comments?post=865"}],"version-history":[{"count":11,"href":"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-json\/wp\/v2\/posts\/865\/revisions"}],"predecessor-version":[{"id":962,"href":"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-json\/wp\/v2\/posts\/865\/revisions\/962"}],"wp:attachment":[{"href":"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-json\/wp\/v2\/media?parent=865"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-json\/wp\/v2\/categories?post=865"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/60-428\/f2021\/wp-json\/wp\/v2\/tags?post=865"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}